OpenCv-Mat

951 阅读5分钟

Mat 与Bitmap 区别

Mat 是OpenCv 中用来存储图像信息的 内存对象。Bitmap是Android 提供的图像对象

Mat 相关Api

// 加载Mat,第二个参数表示加载图像类型
IMREAD_UNCHANGED=-1,表示不改变加载图像类型,可以包含透明通道
IMREAD_GRAYSCALE=0, 表示加载图像为灰色图像
IMREAD_COLOR=1,加载图像为彩色图像
Mat src=Imgcodecs.imread(path,Imgcodesc.IMREAD_COLOR)

int width=src.cols();
int height=src.rows()
int dims=src.dims()
int channels = src.channels()
int depth=src.depth()
int type=src.type()

保存文件
Imgcodes.imwrite(path,src)
//Mat 绘制几何形状与文本
        Mat src=Mat.zeros(500,500, CvType.CV_8UC3);
        //椭圆或者弧长
        Imgproc.ellipse(src,new Point(250,250),new Size(100,50),360,0,
                0,new Scalar(0,0,255),2,8,0);

        //文本
        Imgproc.putText(src,"测试",new Point(20,20), Core.FONT_HERSHEY_PLAIN,1.0,new Scalar(255,0,0),2);

        Rect rect = new Rect();
        rect.x=50;
        rect.y=50;
        rect.width=100;
        rect.height=100;
        //矩形
        Imgproc.rectangle(src,rect.tl(),rect.br(),new Scalar(255,0,0),2,8,0);
        //圆形
        Imgproc.circle(src,new Point(400,400),50,new Scalar(0,255,0),2,8,0);

        //线
        Imgproc.line(src,new Point(10,10),new Point(490,490),new Scalar(0,255,0),2,8,0);
        Imgproc.line(src,new Point(10,490),new Point(490,10),new Scalar(255,0,0),2,8,0);

Bitmap和Mat 互转

Mat src=Imgcodes.imread(path)
int width=src.cols();
int height =src.rows();
Bitmap bm=Bitmap.createBitmap(width.height,Bitmap.Config.ARGB_8888);
Mat dst=new Mat();
Imgproc.cvtColor(src,dst,Imgproc.COLOR_BGR2RGBA);
Utils.matToBitmap(dst,bm);
 Bitmap bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
        Mat mat = new Mat();
        //bitmap转mat
        Utils.bitmapToMat(bitmap,mat);
        Imgproc.circle(mat,new Point(mat.cols()/2,mat.rows()/2),50,new Scalar(255,0,0,255),2,8,0);
        //mat 转bitmap
        Utils.matToBitmap(mat,bitmap);
        imageView.setImageBitmap(bitmap);

Mat 像素操作

         Bitmap bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.baidu);
        Mat src = new Mat();
        Utils.bitmapToMat(bitmap,src);
        // 从mat中每次读取一个像素点 
//        byte[] data = new byte[src.channels()];
//        int b=0,g=0,r=0;
//        for (int row=0;row<src.rows();row++){
//            for (int col=0;col<src.cols();col++){
//                src.get(row,col,data);
//                b=data[0]&0xff;
//                g=data[1]&0xff;
//                r=data[2]&0xff;
//                b=255-b;
//                g=255-g;
//                r=255-r;
//                data[0]=(byte)b;
//                data[1]=(byte)g;
//                data[2]=(byte)r;
//                src.put(row,col,data);
//            }
//        }


//        // 每次读取一行像素
//        byte[] data=new byte[src.channels()*src.cols()];
//        int b=0,g=0,r=0;
//        int pv=0;
//        for (int row=0;row<src.rows();row++){
//            src.get(row,0,data);
//            for (int col=0;col<data.length;col++){
//                pv=data[col]&0xff;
//                pv=255-pv;
//                data[col]=(byte)pv;
//            }
//            src.put(row,0,data);
//        }
//        //一次读取全部像素
//        int pv=0;
//        byte[] data=new byte[src.channels()*src.cols()*src.rows()];
//        src.get(0,0,data);
//        for (int i=0;i<data.length;i++){
//            pv=data[i]&0xff;
//            pv=255-pv;
//            data[i]=(byte)pv;
//        }
//        src.put(0,0,data);
        Utils.matToBitmap(src,bitmap);
        imageView.setImageBitmap(bitmap);
        src.release();

特点

  1. 第一张因为频繁访问jni调用效率低,但是内存需求少
  2. 第二种相对第一张读取速度提高,但是内存需求相对第一种大
  3. 第三章效率处理最高,但是内存消耗也是最大的

通道分离和合并

  Bitmap bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.baidu);
        Mat src = new Mat();
        Utils.bitmapToMat(bitmap, src);
        List<Mat> mv = new ArrayList<>();
        Log.e(TAG,src.channels()+"");
        //分离
        Core.split(src, mv);
        for (Mat m : mv) {
            int pv = 0;
            int channels = m.channels();
            Log.e(TAG,"split:"+m.channels());
            int width = m.cols();
            int height = m.rows();
            byte[] data = new byte[channels * width * height];
            m.get(0, 0, data);
            for (int i = 0; i < data.length; i++) {
                pv = data[i] & 0xff;
                pv = 255 - pv;
                data[i] = (byte) pv;
            }
            m.put(0,0,data);
        }
         //合并
        Core.merge(mv,src);
        Utils.matToBitmap(src, bitmap);
        imageView.setImageBitmap(bitmap);
        src.release();

计算均值和标准方差

meanStdDev(Mat src,MatOfDoubble mean,MatofDouble stddev);
src:输入Mat图像
mean:计算各个通道的均值
stddev:计算各个通道的标准方差

二值图像切割

    Bitmap bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.baidu);
        Mat src = new Mat();
        Utils.bitmapToMat(bitmap, src);
        //灰度图
        Mat gray=new Mat();
        Imgproc.cvtColor(src,gray,Imgproc.COLOR_BGR2GRAY);
        //计算均值和标准方差
        MatOfDouble means=new MatOfDouble();
        MatOfDouble stddevs=new MatOfDouble();

        Core.meanStdDev(gray,means,stddevs);
        //显示均值和标准方差
        double[] mean = means.toArray();
        double[] stddev = stddevs.toArray();

        Log.i(TAG,"gray image means : " + mean[0]);
        Log.i(TAG,"gray image stddev : " + stddev[0]);

        //读取像素数组
        int width = gray.cols();
        int height = gray.rows();
        byte[] data = new byte[width * height];
        gray.get(0,0,data);

        //根据均值进行二值切割
        int t=(int)mean[0];
        for (int i=0;i<data.length;i++){
            int pv=data[i]&0xff;
            if(pv>t){
                data[i]=(byte)255;
            }else {
                data[i]=(byte)0;
            }
        }
        gray.put(0,0,data);
        Utils.matToBitmap(gray, bitmap);
        imageView.setImageBitmap(bitmap);
        src.release();

Mat的加减乘除

add(Mat src1,Mat src2,Mat dst)
subtract(Mat src1,Mat src2,Mat dst)
multiply(Mat src1,Mat src2,Mat dst)
divide(Mat src1,Mat src2,Mat dst)

src:输入第一个Mat对象
src2:输入第二个Mat对象
dst:输出Mat对象

// 图像权重叠加
addWeighted(Mat src1,double alpha,Mat src2,double beta,double gamma,Mat dst)

src:第一个图像
alpha:混合第一个Mat所占的比重
src2:第二个图像
beta:第二个所占比重
gamma:混合后是否进行亮度矫正(提示或降低)
dst:输出叠加

dst=src*alpha+src2*beta+gamma

bitwise_not(Mat src,Mat dst)//取反
bitwise_and(Mat src1,Mat src2,Mat dst)//与操作
bitwise_or(Mat src1,Mat src2,Mat dst)//或操作
bitwise_xor(Mat src1,Mat src2,Mat dst)异或操作

converScaleAbs(Mat src,Mat dst)//线性绝对值缩放变换
//归一化
normalize(Mat src,Mat dst,double alpha,double beta, int norm_type ,int dttype,Mat mask)
beta:归一化到指定范围的高值
alpha:归一化到指定范围的低值
dytpe:表示输出的dst图像类型,默认-1,表示类型和src相同
mask,表示遮罩层,默认Mat()

在算术运算中,src1和src2 他们的大小和类型必须一致,默认的输出图像类型也一致

 Bitmap bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.timg);
        Mat src = new Mat();
        Utils.bitmapToMat(bitmap, src);
        Mat moon =Mat.zeros(src.rows(),src.cols(),src.type());
        int cx=src.cols()-60;
        int cy=60;
        Imgproc.circle(moon,new Point(cx,cy),50,new Scalar(90,95,234),-1,8,0);
        Mat dst=new Mat();
        Core.add(src,moon,dst);
        Utils.matToBitmap(dst, bitmap);
        imageView.setImageBitmap(bitmap);
        src.release();

提高图像对比度和亮度

  1. 对于RGB色彩图像,亮度越高,像素点对应的RGB值越大越接近255,反正越低
  2. 对比度主要用来描述图像颜色与亮度差异感知,对比度越大,图像对每个像素与周围的差异性越大,整个图像细节越显著
 float b=1;
        float c=1;
   Bitmap bitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.baidu);
        Mat src = new Mat();
        Utils.bitmapToMat(bitmap, src);

        Mat dst1 = new Mat();
        Core.add(src,new Scalar(b,b,b),dst1);
        Mat dst2=new Mat();
        Core.multiply(dst1,new Scalar(c,c,c),dst2);

        Bitmap bm=Bitmap.createBitmap(src.cols(),src.rows(), Bitmap.Config.ARGB_8888);
        Mat result =new Mat();
        Imgproc.cvtColor(dst2,result,Imgproc.COLOR_BGR2RGBA);
        Utils.matToBitmap(result, bm);
        imageView.setImageBitmap(bm);
        src.release();

原文:OpenCv Android 开发实战 参考文章:blog.csdn.net/qq_22329521…