NO.2 Android Opencv 像素处理
程序员文章站
2023-12-25 18:26:39
...
零蚀
Mat像素处理
-
从Mat中读取像素数据
- 读取一个像素数据,这种方式就是和bitmap中的读取一个像素点的方式是一样的,将每个像素点进行处理。
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.android); Mat src=new Mat(); Mat dst=new Mat(); Utils.bitmapToMat(bitmap,src); int width = src.width(); int height = src.height(); int channels=src.channels(); byte[] bytes=new byte[channels]; int b=0,g=0,r=0; for (int row = 0; row < height; row++) { for (int cols = 0; cols < width; cols++) { // 获取 src.get(row, cols,bytes); b=bytes[0] & 0xff; g=bytes[1] & 0xff; r=bytes[2] & 0xff; // 修改 b=255-b; g=255-g; r=255-r; // 设置 bytes[0]= (byte) b; bytes[1]= (byte) g; bytes[2]= (byte) r; src.put(row,cols,bytes); } } Imgproc.cvtColor(src, dst,Imgproc.COLOR_BGRA2BGR); Utils.matToBitmap(dst,bitmap); ImageView image = findViewById(R.id.image); image.setImageBitmap(bitmap); src.release(); dst.release();
- 按照每一行来设置像素的信息,这里要注意,上面是
byte[] bytes=new byte[channels*width]; int pv=0; for (int row = 0; row < height; row++) { // 获取一行 src.get(row,0,bytes); for (int cols = 0; cols < bytes.length; cols++) { // 获取每一个的每一个列的元素 pv=bytes[cols] & 0xff; // 修改每一列的元素 pv=255-pv; // 设置进一行的素组信息中 bytes[cols]= (byte) pv; } src.put(row,0,bytes); }
- 一次性全部读取
Utils.bitmapToMat(bitmap,src); int width=src.width(); int height=src.height(); int channel=src.channels(); byte[] bytes=new byte[channel*width*height]; int pv=0; src.get(0,0,bytes); for (int i = 0; i < bytes.length; i++) { pv=bytes[i]&0xff; pv=255-pv; bytes[i]= (byte) pv; } src.put(0,0,bytes); Imgproc.cvtColor(src, dst,Imgproc.COLOR_BGRA2BGR);
-
算数操作
- 将图像拆成多个待合并的单通道图,或单通道合并成多通道图,计算均值和标准差,这个标准差主要可以根据大小判断图像的色彩波动,来判断图像的质量好坏。
Core.split(src,list); // 通道分离,(分离成单通道图) Core.merge(list,src); // 通道合并 // 计算通道均值,标准方差 MatOfDouble average=new MatOfDouble(); MatOfDouble variance=new MatOfDouble(); Core.meanStdDev(src,average,variance); // 显示均值和方差 Log.e("zero","average="+average.toArray()[0]); Log.e("zero","variance="+variance.toArray()[0]);
- 我们可以根据均值设置二值图,(就是两种色彩构建的图图,只用0和255绘制)
src.get(0,0,data); for (int i=0;i<data.length;i++) { pv = data[i] & 0xff; if(pv < average.toArray()[0]){ data[i]=(byte)0; }else{ data[i]=(byte)255; } } src.put(0,0,data);
-
两个图像的加减乘除
- 以加为例,给图片添加红色,这里如果想相加两个个Mat
Utils.bitmapToMat(bitmap,src); // 给图片添加颜色 Core.add(src,new Scalar(255,0,0),dst); Mat result=new Mat(); Imgproc.cvtColor(dst,result,Imgproc.COLOR_BGRA2BGR); Bitmap bitmapRes=Bitmap.createBitmap(dst.width(),dst.height(),Bitmap.Config.ARGB_8888); Utils.matToBitmap(result,bitmapRes); ImageView image = findViewById(R.id.image); image.setImageBitmap(bitmapRes);
- 其他的计算的方法(加减乘除)
add(Mat srcl, Mat src2, Mat dst) subtract(Mat srcl, Mat src2, Mat dst) multiply(Mat srcl, Mat src2, Mat dst) divide(Mat srcl, Mat src2, Mat dst)
- 图像的权重叠加(这个和add的作用机理一致,不一样的是add相当于 1+1 , 而权限总和只能为1),让我们来看看1:1的融合样子。
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.android); Bitmap bitmap2 = BitmapFactory.decodeResource(this.getResources(), R.mipmap.clothes); Mat src=new Mat(); Mat src2 = new Mat(); Utils.bitmapToMat(bitmap,src); Utils.bitmapToMat(bitmap2,src2); Mat dst=new Mat(); /** * @Param src1 第一个输入的mat参数 * @Param alpha 第一个图像所占的权重(权重满足条件是所有权重和为1 alpha + beta = 1) * @Param src2 第二个输入的mat参数 * @Param beta 第二个图像所占的权重 * @Param gamma 亮度 默认值为0 * @Param dst 输出mat */ Core.addWeighted(src,0.6,src2,0.4, 0 ,dst); // Core.add(src,src2,dst); // 给图片添加颜色 Bitmap bitmapRes=Bitmap.createBitmap(src.width(),src.height(),Bitmap.Config.ARGB_8888); // 转化为bitmap Utils.matToBitmap(dst,bitmapRes); image.setImageBitmap(bitmapRes);
-
这里要注意的一点是,合并的两张图像的规格一定要一致,不然就会发生报错,这里这个衣服和android机器人的图像都是 200 x 200 (32bit)的图像。
-
像素操作(⚠️注意 :这里需要在取反前讲图像有透明度的改成没有透明度的格式,不然取反会变形,并且其他的操作,都要求两个图片格式一样)
// 像素值取反,每个像素都255-b/g/r Imgproc.cvtColor(src,src2,Imgproc.COLOR_BGRA2RGB); Core.bitwise_not(src2,result); // 像素或操作 Core.bitwise_or(src,src2,dst); // 像素与操作 Core.bitwise_and(src,src2,dst); // 像素亦或操作 Core.bitwise_xor(src,src2,dst);
- 图像归一化处理(将像素归一化到 0~255之内)
// 将像素值缩放到 0 - 255 之内 Core.convertScaleAbs(src,dst); // 将像素值缩放到 90 - 140 之内 /** * @Param src 表示源数据 * @Param dst 目标数据 * @Param alpha 归一化的最低值 * @Param beta 归一化的最高值 * @Param dtype 输出类型,默认-1源数据类型(NORM_MINMAX 最大最小值诡异算法) * @Param mark 遮罩层 */ // 将像素值缩放到 90 - 140 之内 Core.normalize(src,dst,200,255,Core.NORM_MINMAX,-1,new Mat());
-
最小与最大值归一化算法
- 其实我觉得上面这个算法其实很好理解的,假设这里设置的上下值的差值设为Error(误差beta-alpha),数据里最大误差error(max-min),则我们用数据的单个像素点误差/最大误差 * 设定误差 , 就相当于把图像里的误差值,缩放到了我们设定的误差值上,然后加上我们设定的像素起始值,就是这个像素该有的缩放后的值了。