opencv4android常用变换(终)

opencv4android常用变换(三)

这是opencv4android的第三篇,从这里开始就简单的写,要不我没有时间去学别的了!大家加油。

Laplace 算子

检测边缘的一种算法,是一个二阶导数就是Sobel的导数,可以这么理解,是边界轮廓更加清晰明显。
方法: Laplacian(grayMat,dstMat,-1,3,1,0,Core.BORDER_DEFAULT);

参数说明:原图像,目标图像,深度,内核大小,后三个为默认值。

代码:

    Mat grayMat=new Mat();
    Utils.bitmapToMat(mBitmap,rgbMat);
    Imgproc.GaussianBlur(rgbMat,grayMat,new Size(3,3),0,0,Core.BORDER_DEFAULT);
    Imgproc.cvtColor(grayMat,grayMat,Imgproc.COLOR_BGR2GRAY);
    Imgproc.Laplacian(grayMat,dstMat,-1,3,1,0,Core.BORDER_DEFAULT);
    Utils.matToBitmap(dstMat,dstBitmap);
    dstImage.setImageBitmap(dstBitmap);

效果:

从效果图上来看,确实要比Sobel的边缘检测效果要好很多,能够很明显的看出帽子上羽毛的轮廓。

Canny 边缘检测

Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法, 最优边缘检测的三个主要评价标准是:

  • 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
  • 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
  • 最小响应: 图像中的边缘只能标识一次。
    —引自opencv教程。

方法:Imgproc.Canny(grayMat,dstMat,n,3*n,3,true);

参数:灰度图像,目标图像,最低阈值,最高阈值,内核大小,不知道。

代码:

    Mat grayMat=new Mat();
    Utils.bitmapToMat(mBitmap,rgbMat);
    Imgproc.cvtColor(rgbMat,grayMat,Imgproc.COLOR_BGR2GRAY);
    Imgproc.GaussianBlur(grayMat,grayMat,new Size(3,3),0,0,Core.BORDER_DEFAULT);
    Imgproc.Canny(grayMat,dstMat,n,3*n,3,true);
    Utils.matToBitmap(dstMat,dstBitmap);
    dstImage.setImageBitmap(dstBitmap);

解释一下,先灰度之后高斯平滑,之后在边缘检测。

效果图:

在解释一下,进度条最大值代表最低阈值,也就是第三个参数,第四个参数是第三个的2-3倍最好,我使用3倍,内核是3,opencv教程中使用的归一块平滑,我用的是高斯,可能效果上有所差异,不过轮廓的清晰度还是很好的。

霍夫线变换

霍夫线变换是一种用来寻找直线的方法.
是用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像.

在写这个的时候已经距离我写之前的两个有一个礼拜的时间了。这个霍夫线变化实在是有点费劲,主要是在容器的创建和使用上,完全搞不懂,如果有会的希望能给我留言,交流一下, QQ755457743.标准的霍夫线变换没写,因为那个容器没法弄,搞了好几天都没搞好,都准备弃了,统计概率霍夫线变换写出来了,不过感觉不对啊,跟opencv教程上的差好多,不过也算是弄出来了,就发一下看看。
方法: HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap)
参数:

  • image: 边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)
  • lines: 储存着检测到的直线的参数对 (x_{start}, y_{start}, x_{end}, y_{end}) 的容器
  • rho : 参数极径 r 以像素值为单位的分辨率. 我们使用 1 像素.
  • theta: 参数极角 \theta 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
  • threshold: 要”检测” 一条直线所需最少的的曲线交点
  • minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.
  • maxLineGap: 能被认为在一条直线上的亮点的最大距离.

其中最费劲的就是这个lines容器,Mat对象。完全不知道怎么写。各种尝试。最后在stackoverflow看到一个人的回答,参照他的写法才勉强弄出图像的。

代码:

 Mat srcMat=new Mat();
    Mat dstMat=new Mat();
    Mat thresholdImage=new Mat();
    Utils.bitmapToMat(mBitmap,srcMat);
    Imgproc.cvtColor(srcMat,thresholdImage,Imgproc.COLOR_BGR2GRAY,4);
    Imgproc.cvtColor(srcMat,dstMat,Imgproc.COLOR_BGR2RGB,4);
    Imgproc.Canny(thresholdImage,thresholdImage,50,200,3,true);
    Mat lines=new Mat();
    int threshold=50,minLineSize=50,lineGap=10;
    Imgproc.HoughLinesP(thresholdImage,lines,1,1,n,n,lineGap);
//        Imgproc.HoughLines(thresholdImage,lines,1,1,n,0,0);
    for(int i=0;i

效果图:

可以看出来,只是有线的效果,而且只有在阈值特别低的情况下才能明显的感觉到有窗户,感觉是我写的不对。在上面的代码中,主要的坑就是在第二个参数坐标的容器,卡了好久,完全没有思路,现在的这种方式也是借鉴来的,自己加了一些改动,可能是自己对于矩阵这个容器的理解不是很深刻,上面你的代码我也不是很理解,矩阵搞得每一个元素都存储了两个点的坐标,也就是一条直线的起点和终点,我不知道对不对。

霍夫圆变换

跟霍夫线变换类似用于检测圆的,这个写的没问题,不过需要根据阈值拉调整。

方法:
HoughCircles(Mat image, Mat circles, int method, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius)
参数:

  • image: 输入图像 (灰度图)
  • circles: 存储下面三个参数: x_{c}, y_{c}, r 集合的容器来表示每个检测到的圆.
  • CV_HOUGH_GRADIENT: 指定检测方法. 现在OpenCV中只有霍夫梯度法
  • dp = 1: 累加器图像的反比分辨率
  • min_dist = src_gray.rows/8: 检测到圆心之间的最小距离
  • param_1 = 200: Canny边缘函数的高阈值
  • param_2 = 100: 圆心检测阈值.
  • min_radius = 0: 能检测到的最小圆半径, 默认为0.
  • max_radius = 0: 能检测到的最大圆半径, 默认为0

代码:

 Mat src=new Mat();
    Mat dst=new Mat();
    Mat gray=new Mat();
    Utils.bitmapToMat(mBitmap,src);
    Imgproc.cvtColor(src,gray,Imgproc.COLOR_BGR2GRAY);
    Imgproc.GaussianBlur(gray,gray,new Size(9,9),2,2);
    Mat circles=new Mat();
    Imgproc.HoughCircles(gray,circles,Imgproc.CV_HOUGH_GRADIENT,1,gray.rows()/8,4*n,100,0,0);
    for(int i=0;i

这个代码是没有问题的,效果也是可以的,如果没有达到预期可能是因为param_1的参数问题。

效果图:

可以看到不同的值对应这不同的圆。

Remapping 重映射

把一个图像中一个位置的像素放置到另一个图片指定位置的过程.这个效果没有实现,只实现了像素的挪动没有达到opencv中的效果。

方法:

 remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, int borderMode, Scalar borderValue)

参数:

  • src: 源图像
  • dst: 目标图像,与 src 相同大小
  • map_x: x方向的映射参数. 它相当于方法 h(i,j) 的第一个参数
  • map_y: y方向的映射参数. 注意 map_y 和 map_x 与 src 的大小一致。
  • CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
  • BORDER_CONSTANT: 默认

代码:

 if(rgbMat==null|dstMat==null){
        rgbMat=new Mat();
        dstMat=new Mat();
    }
    Utils.bitmapToMat(mBitmap,rgbMat);
    Mat src_x=new Mat(rgbMat.size(),CvType.CV_32FC1);
    Mat src_y=new Mat(rgbMat.size(),CvType.CV_32FC1);
    for(int j=1;j

效果图:

参照opencv教程中代码,经过自己的理解和改写之后在opencv4android中实现效果就这样,能够看出来确实像素点的位置对调了,但是像素值却发生了改变,不清楚为什么会发生这种情况,个人猜测是因为src_y和src_x的原因,我也尝试了不用的位置偏差,和混合方式,结果都不行,像素值在转换过来之后都发生了改变。至此无果。

结束语

opencv4android到现在已经写了4篇了,从环境搭建道基本使用,说实话我都不知道这个东西是干嘛的,就只是朋友要就学了一点,之后自己感兴趣就多学了一些,不过到这里也就结束了,这一篇是暂时的完结,也不知道以后会不会写, 因为这个东西对于现在的我来说实在是费劲,从图像的知识到C再到opencv,心力交瘁,有时候一个很简单的东西都会卡很久,兴趣也变成无趣了,为自己之前的狂妄自大说个对不起,就到这里了,写不下去。

你可能感兴趣的:(Android)