OpenCV的全称是:Open Source Computer Vision Library。OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。–来自百度。
OpenCV4android是opencv在android上的实现,进行一定配置之后就一个在android中通过Java调用opencv中的功能,可以实现很多不同的效果和进行图片分析,处理等。
作者水平有限,并没有专门学过opencv,也不了解具体的算法实现,这篇文章只是简单的介绍一下opencv4android在android中的使用和相关api,如有误,请斧正。
这篇都有哪些内容:主要就是Imgproc中API的使用,核心(core)模块没有多介绍,一些基础的关于opencv的知识可以在http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/tutorials.html学习,作者本人也是在这个网站学的,而且所有文章中的内容都是根据这个网站所提供的信息,在opencv4android中的实现,欢迎交流。
先介绍这么多,以后还会有更多的内容的。这阅读下面的内容之前,请确定自己的Studio已经配置好了opencv4android,不会的可以去看我上一篇文章。先从简单的来。
平滑 也称 模糊, 是一项简单且使用频率很高的图像处理方法。
在opencv中有四种常用处理方式:
这里先为大家普及两个概念,内核或者说核(Size),锚点(Point)
在我看来,核就是一个物体,用这个物体去扫描图片,使图片产生一系列的变化,锚点就是这个核中额某一个点,在一些特殊需要的情况下可能不在中心位置(我猜的)
具体的每一种滤波器是如何处理图像的我也不会,复制粘贴也不是我的风格,就这样了,直接上代码,看看效果。
private Mat rgbMat,dstMat;
private void changeBitmap(){
if(rgbMat==null|dstMat==null){
rgbMat=new Mat();
Utils.bitmapToMat(mBitmap,rgbMat);
//双边转换
// Imgproc.cvtColor(rgbMat,rgbMat,Imgproc.COLOR_BGR2RGB);
dstMat=new Mat(rgbMat.size(),rgbMat.type());
}
Log.d("TAG","rgb:"+rgbMat.type()+"/"+rgbMat.size()+"/"+dstMat.size()+"/"+dstMat.type());
switch (operation){
case 0: Imgproc.blur(rgbMat,dstMat,new Size(2*n+1,2*n+1),new Point(-1,-1)); break;
case 1: Imgproc.GaussianBlur(rgbMat,dstMat,new Size(2*n+1,2*n+1),0,0); break;
case 2: Imgproc.medianBlur(rgbMat,dstMat,2*n+1); break;
case 3: Imgproc.bilateralFilter(rgbMat,dstMat,10,75,75); break;
}
Utils.matToBitmap(dstMat,dstBitmap);
dstImage.setImageBitmap(dstBitmap);
}
说一下流程:
四种不同的平滑方式:
CvException [org.opencv.core.CvException: cv::Exception: /Volumes/Linux/builds/master_pack-android/opencv/modules/imgproc/src/smooth.cpp:3145: error: (-215) (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.data != dst.data in function void cv::bilateralFilter_8u(const cv::Mat&, cv::Mat&, int, double, double, int)
]
可以看一下错误信息,对于一个从没有学过C++,opencv的人来说这是什么?完全不理解好不好,之后就是上网查资料,看见了这个。
CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) &&
src.type() == dst.type() && src.size() == dst.size() &&
src.data != dst.data );
这个是赵春江先生/女士在CSDN上一篇博客的内容,是不是特别相似,不过到这我也不明白,所以就百度了下 CV_Assert 这个方法,说是C++中的assert()方法类似,括号内为false会抛一个异常,到这我就知道问题出在哪里了,之后就是解决问题吧,又是坑啊,在opencv4android中并没有明确的CV_8UC1或者CV_8UC3常量,我就是想把type设置成指定类型的我都不知道类型是多少,不过,经过我不断的尝试(就是一个个转换看哪个不报错而已),终于也可以了,可以看见:
Imgproc.cvtColor(rgbMat,rgbMat,Imgproc.COLOR_BGR2RGB);
使用COLOR_BGR2RGB这个转换方式可以将图片转换成CV_8UC3,可能会有人问你怎么知道到RGB就是CV_8UC3,不要嘲笑我,我是真不知道8位无符号3通道就是RGB,不过我有一个灵活的大脑和勤劳的双手,少年看这里:
The input Mat object has to be of the types 'CV_8UC1' (gray-scale), 'CV_8UC3' (RGB) or 'CV_8UC4' (RGBA).
这个是Mat类中倒数第二个方法的注释,可以看到’CV_8UC3’ 就是RGB,而’CV_8UC1’就是灰度图,用android中的数值应该怎么表示那?告诉你:
不要问我怎么知道的,我会告诉你每次转换之后我都打印了一下type了吗?,现在这个问题算是解决了,只要将BGR图片转换成RGB的就可以,至于为什么,我不知道。。。。效果图
这个是正常BGR模式下的效果图,可以看出来在前三种模式下,相同内核大小,高斯滤波器的平滑效果明显要弱于其他两种,具体的不多说了,看下RGB模式下的效果:
可以看出来在初始情况下,图片就已经转换为RGB模式了,颜色上有明显的不同,之后是四种平滑方式的对比实现,可以根据个人喜好去选择不同的平滑方式。
腐蚀和膨胀是最基本的形态学操作,之后会学到的其他形态学变化都是基于这两种所实现的,形态学操作,简单来讲,形态学操作就是基于形状的一系列,图像处理操作,通过将结构元素作用于输入图像来产生输出图像。
参考代码:
private Mat rgbMat,dstMat;
//腐蚀
private void changeBitmap(){
if(rgbMat==null|dstMat==null){
rgbMat=new Mat();
dstMat=new Mat();
Utils.bitmapToMat(mBitmap,rgbMat);
}
//设置内核形状和内核大小
Mat kernel=Imgproc.getStructuringElement(shape,new Size(2*n+1,2*n+1),new Point(n,n));
Imgproc.erode(rgbMat,dstMat,kernel);
Utils.matToBitmap(dstMat,dstBitmap);
dstImage.setImageBitmap(dstBitmap);
}
//膨胀
private void grayBitmap(){
if(rgbMat==null|dstMat==null){
rgbMat=new Mat();
dstMat=new Mat();
Utils.bitmapToMat(mBitmap,rgbMat);
}
//设置内核形状和内核大小
Mat kernel=Imgproc.getStructuringElement(shape,new Size(2*n+1,2*n+1),new Point(n,n));
Imgproc.dilate(rgbMat,dstMat,kernel);
Utils.matToBitmap(dstMat,dstBitmap);
dstImage.setImageBitmap(dstBitmap);
}
可以看到大部分的代码都是相同的就是函数名不一样,也没有什么好解释的,看效果:
关于内核的形状有三种,分别是矩形,交错形和椭圆形,可以通过腐蚀时看出来三种不同的内核对腐蚀效果的影响。
在掌握了基础的两种变化之后,可以学习更复杂一点的形态学变化方式:
所使用的函数统一为morphologyEx(Mat src, Mat dst, int op, Mat kernel),其中src为原图像,dst为输出图像,op为操作类型,kernel为内核。
忘了介绍了,在opencv4android中关于内核形状和形态学方法是有常量表示的:
形态学方法:
内核形状:
至于这些内容是从哪找的,可以去参考Imgproc中的常量。上代码~~~~·
private void changeBitmap() {
if(rgbMat==null|dstMat==null){
rgbMat=new Mat();
dstMat=new Mat();
Utils.bitmapToMat(mBitmap,rgbMat);
}
Mat kernel=Imgproc.getStructuringElement(shape,new Size(2*n+1,2*n+1),new Point(n,n));
Imgproc.morphologyEx(rgbMat,dstMat,operation,kernel);
Utils.matToBitmap(dstMat,dstBitmap);
Toast.makeText(MainActivity.this,"OK",Toast.LENGTH_SHORT).show();
dstImage.setImageBitmap(dstBitmap);
}
效果图如下:
个人比较喜欢黑猴子,不知道大家喜欢哪一个?值得注意就是当采用black加椭圆内核的时候,运行起来有比较严重的延迟,界面被阻塞了,实际应用中应该采用异步的方式去使用,更多的就需要大家去实践了。如果有不理解的可以留言,这篇就讲这么多,剩下的内容我需要去整理一下,先到这里。