NO.2 Android Opencv 像素处理

本文详细介绍了在Android中使用OpenCV进行像素处理,包括读取和设置像素数据、计算均值和标准差、图像的加减乘除操作、权重叠加、像素归一化处理等。特别强调了在进行像素操作时需要注意的图像格式一致性问题,以及如何避免透明度导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

零蚀


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();
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amw24GsS-1599224494984)(media/15979947980387/15979954488407.jpg)]

    • 按照每一行来设置像素的信息,这里要注意,上面是
        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]);
    

    均 值 μ = 1 n ∑ i = 0 n x i 均值\mu= \frac{1}{n} \sum_{i=0}^n x_i μ=n1i=0nxi

    标 准 方 差 s t d d e v = ∑ i = 0 n ( x i − μ ) 2 n − 1 标准方差stddev = \sqrt{\frac{\sum^n_{i=0}{(x_i-\mu)^2}}{n-1}} stddev=n1i=0n(xiμ)2

    • 我们可以根据均值设置二值图,(就是两种色彩构建的图图,只用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);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tO0K6mnL-1599224494986)(media/15979947980387/15983568032106.jpg)]

  • 两个图像的加减乘除
    • 以加为例,给图片添加红色,这里如果想相加两个个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);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dfziD4MO-1599224494988)(media/15979947980387/15983599147239.jpg)]

    • 其他的计算的方法(加减乘除)
    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);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7tklnLYD-1599224555515)(media/15979947980387/15991864663022.jpg)]

    • 这里要注意的一点是,合并的两张图像的规格一定要一致,不然就会发生报错,这里这个衣服和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);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R6DFw579-1599224555526)(media/15979947980387/15991894706506.jpg)]

    • 图像归一化处理(将像素归一化到 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());
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dYGvoK3E-1599224555527)(media/15979947980387/15992188266181.jpg)]

    • 最小与最大值归一化算法

      d s t = ( x − m i n m a x − m i n ) ∗ ( b e t a − a l p h a ) + a l p h a dst=(\frac{x-min}{max-min})*(beta-alpha)+alpha dst=(maxminxmin)(betaalpha)+alpha

      • 其实我觉得上面这个算法其实很好理解的,假设这里设置的上下值的差值设为Error(误差beta-alpha),数据里最大误差error(max-min),则我们用数据的单个像素点误差/最大误差 * 设定误差 , 就相当于把图像里的误差值,缩放到了我们设定的误差值上,然后加上我们设定的像素起始值,就是这个像素该有的缩放后的值了。

🔗 前言
🔗 Android Opencv篇
🔗 NO.1 Android Opencv 初见
🔗 NO.3 Android Opencv 图像处理
🔗 NO.4 Android Opencv 特征检测
🔗 NO.5 Android Opencv 相机人脸识别
🔗 NO.6 Android Opencv OCR & 积分图
🔗 NO.7 Android Opencv 人脸美颜
🔗 NO.8 Android Opencv 眼球跟踪

<think>嗯,用户想了解OpenCV中的minMaxLoc函数的用法和示例。首先,我需要回忆一下这个函数的作用。minMaxLoc主要用于在数组中查找最小值和最大值,并返回它们的位置。用户可能是在处理图像时,比如在图像中寻找最亮或最暗的,这时候这个函数就很有用。 接下来,我需要确认函数的参数和返回值。根据之前的了解,函数原型应该是cv::minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())。参数包括输入数组、最小值、最大值、最小值位置、最大值位置和掩膜。要注意的是,输入数组应该是单通道的,否则可能需要先转换颜色空间或者分通道处理。 然后,用户可能需要具体的示例代码,比如如何在Python中使用这个函数。比如加载图像,转换为灰度图,然后应用minMaxLoc。这时候需要确保代码正确,比如使用cv2.imread的正确路径,以及正确处理返回的值。另外,如果图像是多通道的,可能需要先分割通道,再在每个通道上调用函数,或者在灰度图上使用。 用户可能还会关心函数的应用场景,比如在模板匹配中找到最佳匹配位置,或者在直方图中寻找峰值。这时候需要举一些实际例子,比如在匹配后使用minMaxLoc获取最大值的位置作为最佳匹配。 另外,需要注意函数在处理多通道数据时的限制,必须使用单通道数组。如果有用户使用了多通道图像,可能需要提醒他们先进行通道分离或转换为灰度图。此外,掩膜参数的使用也是一个需要注意的地方,可以用来指定感兴趣的区域。 还要检查是否有相关的引用内容可以支持回答。比如引用[1]提到OpenCV支持多种编程语言,包括Python,所以Python示例是合适的。引用[2]中的代码展示了OpenCVAndroid中的加载,但用户的问题可能更多关注函数本身,所以可能不需要直接引用这部分。引用[3]提到TrainData类,可能与当前问题无关,可以忽略。 最后,生成相关问题的时候,应该围绕函数的扩展使用、注意事项、与其他函数的对比,以及实际应用案例。比如性能分析、多通道处理、与minMaxIdx的区别,以及在图像处理中的具体应用。</think>以下为OpenCV中`minMaxLoc`函数的详细说明及使用指南: ### 一、函数定义与作用 `cv::minMaxLoc`用于在单通道数组(如灰度图像)中查找全局最小值和最大值及其坐标位置,函数原型为: ```cpp void cv::minMaxLoc( InputArray src, double* minVal, double* maxVal = 0, Point* minLoc = 0, Point* maxLoc = 0, InputArray mask = noArray() ) ``` 其中`src`必须为单通道矩阵(二维数组)[^1] ### 二、Python代码示例 ```python import cv2 import numpy as np # 创建测试图像 img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(img) print(f"最小值:{min_val} @ {min_loc}") print(f"最大值:{max_val} @ {max_loc}") ``` 该代码将输出图像中最暗像素(最小值)和最亮像素(最大值)的坐标及数值 ### 三、核心应用场景 1. **图像分析**:快速定位图像中的亮度极值 2. **模板匹配**:配合`matchTemplate`函数寻找最佳匹配位置 ```python result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(result) ``` 3. **直方图分析**:寻找直方图峰值位置 ### 四、关键注意事项 1. 输入数组必须是单通道(多通道数据需先分通道处理2. 支持掩膜操作,可限定检测区域 3. 对多极值情况只会返回第一个出现的极值位置 ### 五、扩展函数对比 当需要处理多维数组时,应使用`cv::minMaxIdx`函数,该函数支持多维索引返回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值