NO.2 Android Opencv 像素处理

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

零蚀


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 眼球跟踪

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

零蚀zero eclipse

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

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

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

打赏作者

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

抵扣说明:

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

余额充值