You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

p5.js中如何通过冒泡排序将排序后像素恢复为原始图像?

问题根因

你当前的反向逻辑无法还原原始图像的核心原因是:像素完成正向排序后,原始像素的位置信息已经完全丢失,单纯反转冒泡排序的比较逻辑和遍历顺序,只会将图像从色相升序排列改为色相降序排列,不可能回到初始的原始图像状态。你最初设想的存储原始像素位置/原始像素数据的思路才是正确的。

你的操作合理性判断

  • 你认为正确的两个操作:修改比较运算符、两个分支都调用loadPixels()和updatePixels(),逻辑是正确的,只是只能实现正反向的色相排序,无法还原原图。
  • 你不确定的两个操作:反转for循环遍历顺序、修改相邻像素索引为(j, i - 1),符合反向冒泡排序的实现逻辑,本身没有问题。
  • 你提到的循环触发问题,是因为你在else分支中没有更新counter,也没有加还原完成的判断逻辑,所以程序会永远卡在反向排序分支中。

实现方案

  1. 加载原图后立即存储一份原始像素数据,这份数据全程不修改,作为还原的基准。
  2. 新增状态变量标记当前执行阶段:正向排序、反向还原、重置待重新排序。
  3. 反向还原阶段以原始像素的色相为基准做冒泡交换,还原完成后直接重置为原始像素保证100%恢复。
  4. 新增阶段切换逻辑,还原完成后自动重置状态触发下一轮正向排序。

修改后代码

let panel;
let originalPixels = [];
let counter = 0;
const sc = 2;
const frameW = 20;
// 状态标记:0=正向排序 1=反向还原
let state = 0;
// 正向排序迭代阈值
const SORT_THRESHOLD = 3200000;

function preload() {
  panel = loadImage("https://www.paulwheeler.us/files/Burano-island-Venice.jpg");
}

function setup() {
  createCanvas(
    sc * (panel.width + 2 * frameW),
    sc * (panel.height + 2 * frameW)
  );
  pixelDensity(1);
  // 加载完成后存储原始像素
  panel.loadPixels();
  originalPixels = [...panel.pixels];
}

function draw() {
  panel.loadPixels();
  
  if (state === 0) {
    // 正向排序阶段
    for (let i = 0; i < panel.height - 1; i++) {
      for (let j = 0; j < panel.width; j++) {
        counter++;
        if (hue(fGetPanelPixel(j, i)) > hue(fGetPanelPixel(j, i + 1))) {
          let hold = fGetPanelPixel(j, i + 1);
          fSetPanelPixel(j, i + 1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);
        }
      }
    }
    // 达到阈值切换到还原阶段
    if (counter >= SORT_THRESHOLD) {
      state = 1;
      counter = 0;
    }
  } else {
    // 反向还原阶段:以原始像素为基准交换
    let swapCount = 0;
    for (let i = panel.height - 1; i > 0; i--) {
      for (let j = 0; j < panel.width; j++) {
        const currentHue = hue(fGetPanelPixel(j, i));
        const targetHue = hue(fGetOriginalPixel(j, i));
        const prevHue = hue(fGetPanelPixel(j, i - 1));
        const prevTargetHue = hue(fGetOriginalPixel(j, i - 1));
        // 如果当前位置像素的色相和原始目标差距比上一个大,就交换
        if (Math.abs(currentHue - targetHue) < Math.abs(prevHue - prevTargetHue)) {
          let hold = fGetPanelPixel(j, i - 1);
          fSetPanelPixel(j, i - 1, fGetPanelPixel(j, i));
          fSetPanelPixel(j, i, hold);
          swapCount++;
        }
      }
    }
    counter++;
    // 连续多帧没有交换说明还原完成,重置为初始状态,切换回正向排序
    if (swapCount === 0 || counter > SORT_THRESHOLD) {
      // 直接重置为原始像素保证完全还原
      panel.pixels = [...originalPixels];
      state = 0;
      counter = 0;
    }
  }

  panel.updatePixels();
  image(panel, sc * frameW, sc * frameW, sc * panel.width, sc * panel.height);
}

function fGetPanelPixel(x, y) {
  const index = 4 * (y * panel.width + x);
  return [
    panel.pixels[index],
    panel.pixels[index + 1],
    panel.pixels[index + 2],
  ];
}

function fSetPanelPixel(x, y, c) {
  const index = 4 * (y * panel.width + x);
  panel.pixels[index] = c[0];
  panel.pixels[index + 1] = c[1];
  panel.pixels[index + 2] = c[2];
}

// 读取原始像素的工具函数
function fGetOriginalPixel(x, y) {
  const index = 4 * (y * panel.width + x);
  return [
    originalPixels[index],
    originalPixels[index + 1],
    originalPixels[index + 2],
  ];
}

配套HTML代码保持不变:

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

内容的提问来源于stack exchange,提问作者idma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:45:09