内容简介:目前主要通过Processing作为交互界面,所有的图像最后要通过Processing展示。一、Processing图像的使用格式首先,看Processing的图像对格式的要求。
目前主要通过Processing作为交互界面,所有的图像最后要通过Processing展示。
一、Processing图像的使用格式
首先,看Processing的图像对格式的要求。
Processing的图像使用 PImage 类封装(有图有真相)。
这是 PImage 的缺省构造方法,默认的图像格式就是 ARGB,也就是使用4个通道表达图像的像素 (alpha, red, green, and blue)
这是检查图像的像素,如果任何一个像素包含 alpha 通道(透明度),则格式设定为 ARGB !
这里展示的这两个方法,想表达的意思是: Processing 环境下,需要的图像格式的正确顺序是 ARGB ,请记住这个顺序!
二、OpenCV使用的图像格式
问题来了:point_down:
OpenCV使用的图像格式是 BGR ! 为什么?
早期开发者使用BGR作为颜色的空间的原因在于:那个时候的BGR格式在相机制造厂商和软件提供商之间比较受欢迎。 例如:在Windows中,当使用 COLORREF 指定颜色值时,使用BGR格式0x00bbggrr。 更多看这里 --> https://www.learnopencv.com/why-does-opencv-use-bgr-color-format/
前面的OpenCV4从摄像头获取的视频数据,每一帧都是BGR的格式。
虽然 OpenCV4提供了图像格式转换类 Imgproc ( 官方Java doc ),提供了大量的图像格式转换方法(下面是其中的一部分),
static int |
COLOR_mRGBA2RGBA |
static int |
COLOR_RGB2BGR |
static int |
COLOR_RGB2BGR555 |
static int |
COLOR_RGB2BGR565 |
static int |
COLOR_RGB2BGRA |
static int |
COLOR_RGB2GRAY |
static int |
COLOR_RGB2HLS |
static int |
COLOR_RGB2HLS_FULL |
static int |
COLOR_RGB2HSV |
static int |
COLOR_RGB2HSV_FULL |
static int |
COLOR_RGB2Lab |
static int |
COLOR_RGB2Luv |
static int |
COLOR_RGB2RGBA |
static int |
COLOR_RGB2XYZ |
static int |
COLOR_RGB2YCrCb |
static int |
COLOR_RGB2YUV |
static int |
COLOR_RGB2YUV_I420 |
static int |
COLOR_RGB2YUV_IYUV |
static int |
COLOR_RGB2YUV_YV12 |
static int |
COLOR_RGBA2BGR |
static int |
COLOR_RGBA2BGR555 |
static int |
COLOR_RGBA2BGR565 |
static int |
COLOR_RGBA2BGRA |
static int |
COLOR_RGBA2GRAY |
static int |
COLOR_RGBA2mRGBA |
static int |
COLOR_RGBA2RGB |
static int |
COLOR_RGBA2YUV_I420 |
static int |
COLOR_RGBA2YUV_IYUV |
static int |
COLOR_RGBA2YUV_YV12 |
但是,没有直接将 BGR格式直接转换为 ARGB 格式的方法!
前面的程序使用: Imgproc.cvtColor(tmp, src, Imgproc.COLOR_BGR2RGBA);
只能将图像格式从BGR装换到 RGBA,而Processing需要的格式是 ARGB !
这就是导致上一篇文章中图像颜色失真的原因了!
三、解决方法
OpenCV提供了一个混合(颜色)通道的方法 Core.mixChannels( ),可以实现不同通道的颜色交换!
就是他了!
1、原来的方法
draw( )方法如下:
void draw() { background(0); Mat tmp = new Mat(); cap.read(tmp); Imgproc.cvtColor(tmp, fm, Imgproc.COLOR_BGR2RGBA); PImage img = matToImg(fm); image(img, 0, 0); tmp.release(); }
2、修改后的方法
draw() 方法如下:
void draw() { background(0); Mat tmp = new Mat(); Mat src = new Mat(); cap.read(tmp); Imgproc.cvtColor(tmp, src, Imgproc.COLOR_BGR2RGBA); fm = src.clone(); ArrayList<Mat> srcList = new ArrayList<Mat>(); ArrayList<Mat> dstList = new ArrayList<Mat>(); Core.split(src, srcList); Core.split(fm, dstList); Core.mixChannels(srcList, dstList, new MatOfInt(0, 1, 1, 2, 2, 3, 3, 0)); Core.merge(dstList, fm); PImage img = matToImg(fm); image(img, 0, 0); src.release(); tmp.release(); }
三、解释一下
1、创建两个空矩阵 src、tmp;
Mat tmp = new Mat(); Mat src = new Mat();
2、将图像的一帧数据读入 tmp 矩阵;
cap.read(tmp);
3、将 tmp 矩阵的图像格式由 BGR 转换为 RGBA,保存到 src 中;
Imgproc.cvtColor(tmp, src, Imgproc.COLOR_BGR2RGBA);
4、克隆一个 src 为 fm;
fm = src.clone();
这时候,src 和 fm 的内容相同的、都是转换成 RGBA 格式的图像信息;
5、创建两个ArrayList ,把两个矩阵src和fm转换成一维数组srcList和dstList;
ArrayList<Mat> srcList = new ArrayList<Mat>(); ArrayList<Mat> dstList = new ArrayList<Mat>(); Core.split(src, srcList); Core.split(fm, dstList);
6、使用Core.mixChannels() 交换两个一维数组指定位置的数据,将RGBA 的数据交换成 ARGB 数据( 后面说怎么指定位置 )把需要的数据保存到 dstList 中;
Core.mixChannels(srcList, dstList, new MatOfInt(0, 1, 1, 2, 2, 3, 3, 0));
这时候,dstList 一维数组保存的是交换后的 AGRB 数据;
7、然后把 dstList 保存到 fm 矩阵中。
Core.merge(dstList, fm);
8、把 fm矩阵数据转换为PImage。
PImage img = matToImg(fm);
9、显示 PImage 图像。
image(img, 0, 0);
四、OpenCV提供的方法
前面三段中第3步和第6步,都是使用OpenCV提供的方法完成
A)由 BGR 转换为 RGBA;
B)交换一维数组指定位置的数据;
下面用数据进行黑盒测试,看看这两个方法的效果。
1、测试 Imgproc.cvtColor()将 BGR 转换为 RGBA
创建一个空矩阵 src ,一个tmp 矩阵设置一些模拟数据;
import org.opencv.core.*; import org.opencv.videoio.*; import org.opencv.imgproc.*; import java.nio.ByteBuffer; import java.util.ArrayList; void setup(){ size(640,480); System.loadLibrary(Core.NATIVE_LIBRARY_NAME); noLoop(); } void draw(){ background(0); Mat src = new Mat(); Mat tmp = new Mat(new Size(4,3),CvType.CV_8UC4,new Scalar(1,2,3,4)); println("----- before ---"); println("src --->"); println(src.dump()+"\n"); println("tmp --->"); println(tmp.dump()+"\n"); Imgproc.cvtColor(tmp, src, Imgproc.COLOR_BGR2RGBA); println("----- after ---\n"); println("src --->"); println(src.dump()+"\n"); println("tmp --->"); println(tmp.dump()); }
结果:
可以看出,经过 Imgproc.cvtColor(),tmp的 BGRA 格式转换成了 RGBA格式。
2、交换一维数组指定位置的数据
模拟两个矩阵数据,转换成一维数组
import org.opencv.core.*; import org.opencv.videoio.*; import org.opencv.imgproc.*; import java.nio.ByteBuffer; import java.util.ArrayList; void setup(){ size(640,480); System.loadLibrary(Core.NATIVE_LIBRARY_NAME); noLoop(); } void draw(){ background(0); Mat src = new Mat(new Size(4,3),CvType.CV_8UC4,new Scalar(0,1,2,3)); Mat fm = new Mat(new Size(4,3),CvType.CV_8UC4,new Scalar(0,1,2,3)); println("----- before ---"); println("src --->"); println(src.dump()+"\n"); println("fm --->"); println(fm.dump()+"\n"); ArrayList<Mat> srcList = new ArrayList<Mat>(); ArrayList<Mat> dstList = new ArrayList<Mat>(); Core.split(src, srcList); Core.split(fm, dstList); Core.mixChannels(srcList, dstList, new MatOfInt(0, 1, 1, 2, 2, 3, 3, 0)); Core.merge(dstList, fm); println("----- after ---\n"); println("src --->"); println(src.dump()+"\n"); println("fm --->"); println(fm.dump()); }
调用 Core.mixChannels(srcList, dstList, new MatOfInt(0, 1, 1, 2, 2, 3, 3, 0)); 方法得出:
数据从 RGBA 转换为 ARGB。
从上面这张图,讲一下 MatOfInt(0,1,1,2,2,3,3,0)的作用。
把 MatOfInt 的参数,两两一对,组成 (0,1) (1,2) (2,3) (3,0)
表示:
(0,1) R 从 源通道0 -->目标通道1,
(1,2) G 从 源通道1-->目标通道2,
(2,3) B 从 源通道2 -->目标通道3,
(3,0) A 从 源通道3 -->目标通道0
五、结论
只要通过OpenCV的两个方法Imgproc.cvtColor()和Core.mixChannels()方法组合,可以将OpenCV的 BGR格式转换成Processing需要的 ARGB格式。
只要理解了OpenCV的 BGR 格式,Processing的ARGB格式,就可以更好的利用API对图像、视频进行处理。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 浏览器图像转换手册
- 使用PyTorch进行图像风格转换
- 更自由的GAN图像联想:无监督跨类的图像转换模型FUNIT,英伟达&&康奈尔大学
- 英伟达又火了一篇图像转换论文,我们竟然用来吸猫
- img2txt - 将图像转换为各种基于文本的彩色文件
- JavaScript进阶系列-类型转换、隐式类型转换
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。