基于Processing图像序列处理保存导出的流程梳理

做一个基于processing的图像序列处理保存导出的流程梳理。本案例没有什么实质性的目的,仅为流程梳理做演示。


 

准备

把需要处理的影像渲染成序列图片,可以在PR中剪辑并导出PNG序列【格式倒是没什么要求,看质量需求,Processing支持的格式都可以,详情请参考这篇:Processing中PImage类和loadImage()、createImage()函数的相关解析】。
其中的命名规则也没有什么特殊要求,在Processing中都可以适应,如下图:
image
OK!

 

编写PDE

新建速写本,然后保存项目,把序列图片塞进来,一般放在data文件夹中【PS:不放data也可以,采用绝对路径读取】。一切准备就绪。开始写代码。
首先处理单张图片。这里就一并粘上:

PImage moviePicture;  //源影像截图
PGraphics resultPicture;  //处理过后的图片

void settings(){
  size(500, 500);
}

void setup() {
  moviePicture = loadImage("xqdz001.png");  //读取
  moviePicture.filter(GRAY); //灰阶操作
  resultPicture=createGraphics(moviePicture.width, moviePicture.height); //新建图片
  surface.setSize(moviePicture.width*2,moviePicture.height);  //为了方便监视,重新分配窗口大小
  //frameRate(24);
  noLoop();  //因为是单张处理,不用循环
}

void draw() {
  resultPicture.beginDraw();
  ////////////////////////////////////////
  //   这一块是重点,核心算法,很清晰的处理方式
  //   即遍历每个像素,对比像素信息,然后填充给新的像素块
  ////////////////////////////////////////
  for (int i = 0; i < width; ++i) {
    for (int j = 0; j < height; ++j) {
      color cc = moviePicture.get(i, j);
      if (brightness(cc) > 200) {   //如果亮度大于200 (区间 0 - 255)
        resultPicture.set(i, j, cc);
      } else { 
        color cl=color(0, 0, 0); //没有达到亮度的以黑色填充
        resultPicture.set(i, j, cl); 
      }
    }
  }
  ////////////////////////////////////////
  resultPicture.endDraw();

  image(moviePicture, 0, 0);
  image(resultPicture,moviePicture.width,0);
  // 有条件可以建立独立窗口监视
  
  resultPicture.save("result.png");  //导出处理后的图片
}

得到结果:
image
很显然,我的做法是为了提取影像中最亮的像素,即影片中光剑的内容以及各种反光。

接下来

修改代码,使之匹配处理多张图片,即批处理。做法有很多,可以把loadImage读取逻辑、图像处理、保存等过程封装成单独一个个模块,也可以简化一点,直接换字符读取。

PImage moviePicture;  //源影像截图
PGraphics resultPicture;  //处理过后的图片
int frame = 0;  //帧数累计,方便得到图片名字、读取、保存

void settings(){
  size(500, 500);
}

void setup() {
  moviePicture = loadImage("xqdz"+nf(frame,3)+".png");  //读取
  moviePicture.filter(GRAY); //灰阶操作
  resultPicture=createGraphics(moviePicture.width, moviePicture.height); //新建图片
  surface.setSize(moviePicture.width*2,moviePicture.height);  //为了方便监视,重新分配窗口大小
  //frameRate(24);
  //noLoop();  //因为要批处理了,所以把它关掉
}

void draw() {
  
  resultPicture.beginDraw();
  ////////////////////////////////////////
  //   这一块是重点,核心算法,很清晰的处理方式
  //   即遍历每个像素,对比像素信息,然后填充给新的像素块
  ////////////////////////////////////////
  for (int i = 0; i < width; ++i) {
    for (int j = 0; j < height; ++j) {
      color cc = moviePicture.get(i, j);
      if (brightness(cc) > 200) { 
        resultPicture.set(i, j, cc);
      } else { 
        color cl=color(0, 0, 0);
        resultPicture.set(i, j, cl); 
      }
    }
  }
  ////////////////////////////////////////
  resultPicture.endDraw();

  image(moviePicture, 0, 0);
  image(resultPicture,moviePicture.width,0);
  // 有条件可以建立独立窗口监视
  
  resultPicture.save(dataPath("") + "\\result\\result"+ nf(frame,3)+".png");  //导出处理后的图片,路径为data\result文件夹下
  frame ++;
  moviePicture = loadImage("xqdz"+nf(frame,3)+".png");  //读取
  moviePicture.filter(GRAY); //灰阶操作
}

运行起来便得到结果:
image
如果你照搬我的写法,哈哈,是有bug的!因为并没有设定取值范围,即超出帧数后,就读不到图片了,会报空指针异常如下:
image
不过也无所谓,因为这不需要实时运行看结果的,正好自己就结束了,哈哈~~~
正常的做法:

frame ++;
  if(frame >= 600)
  {
    noLoop();
    println("Finished!");
    exit();  //退出程序
  }

很简单的逻辑,超出阈值让它停止并结束。

 

延伸

上面的结果是不带透明通道的。如果想要光留下高亮部分,其他部分没有信息,可以这么来设定:

  resultPicture.beginDraw();
  resultPicture.background(0,0);  //每次刷新图片,注意`background`函数是可以带alpha通道权重值参数的!
  ////////////////////////////////////////
  //   这一块是重点,核心算法,很清晰的处理方式
  //   即遍历每个像素,对比像素信息,然后填充给新的像素块
  ////////////////////////////////////////
  for (int i = 0; i < width; ++i) {
    for (int j = 0; j < height; ++j) {
      color cc = moviePicture.get(i, j);
      if (brightness(cc) > 200) { 
        resultPicture.set(i, j, cc);
      } else { 
        color cl=color(0, 0, 0, 0);  //不填充任何颜色信息 ,此句可省略
        resultPicture.set(i, j, cl); 
      }
    }
  }
  ////////////////////////////////////////
  resultPicture.endDraw;

这样得到的实时监视画面如下:
image
得到的图片如下:
image

 

结语

Processing处理图像是比较灵活的,没有条条框框,随心所欲。。。只要抓好几个要点,即流程重点:

  1. 确保图片对象存在并且Processing有权读取
  2. 遍历图片像素,计算处理,把新的结果输出到新图片上
  3. 保存时注意通道的相关细节,还要注意路径、命名等

其他的并没有什么难点。如果想要处理得理想,就得在像素处理模块上下文章,学学图形学,看看卷积、形态学、深度学习等知识!有需要补充的另开篇幅再总结,结束!