zoukankan      html  css  js  c++  java
  • 基于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
    esult文件夹下
      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. 保存时注意通道的相关细节,还要注意路径、命名等

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

  • 相关阅读:
    多项式插值取模哈希标记法
    AC自助机
    [OIBH] 糖果盒(Candy Box)——又一个最大子矩形
    windows phone 之ListBox数据绑定
    WP学习笔记
    为TextArea添加maxlength属性
    让整个网页(LOGO图片)色调全部变灰的方法(CSS写法)
    JS调试加断点
    Container.ItemIndex 获取到行的序号
    c# Invoke 与 BeginInvoke
  • 原文地址:https://www.cnblogs.com/sharpeye/p/15346459.html
Copyright © 2011-2022 走看看