opencv学习周报(下)

Opencv学习:

(1)基本的opencv数据类型的容器

(2)基本的函数学习(如输入输出,延时函数等)

(3)基础学习:

               (1) 算数与几何操作

       (2) LUT查找表

    (3) 伪彩色与颜色表

    (4) 图像通道分离与合并

    (5) 色彩空间转换

    (6) 像素统计

    (7) 图像几何操作与图形绘制

    (8) 规则ROI与不规则ROI提取

         (9) 图像直方图

(4)空间滤波,边缘检测,图像复原与重建:

        (1)图像卷积基本函数

   (2)高斯,中值,均值卷积函数   

             (3)   图像噪声和去噪

   (4)边缘保留滤波(高斯双边,非局部均值,均值迁移)

   (5)图像梯度(几种算子)

   (6)图像锐化:拉普拉斯和USM两种方法

   (7)Canny边缘检测   

(5)图像金字塔:

          (1)高斯与拉普拉斯

          (2)金字塔重建

(6) 关于图像各种处理

                           (1)模板匹配

                           (2)图像二值化(全局阈值与自适应)         

                           (3)图像的连通组件分析    (实验,未完成)    

                            (4)图像轮廓(树形层次、编码方式、最小外接矩形、面积与周长)加上 轮廓拟合(直线 圆 椭圆之类的)

                           (5)图像距(几何矩、中心矩、HU 矩)

           (6)霍夫变换(直线与圆)
           (7)形态学基础(腐蚀、膨胀、开闭操作)
(8)形态学操作(梯度、击中击不中、顶帽与黑帽)
(9)透视变换与几何变换

(10)轮廓逼近与编码

 

 


 

绿色内容参见:https://www.cnblogs.com/MrMKG/p/16120640.html

灰色内容为待补充内容,对于识别一些简单的物体,数字传给单片机没用,因此未学。

 


   (1)模板匹配

模板匹配不是完美的。尽管它有很多优点,但是如果输入图像中存在变化的因素,包括旋转、缩放、视角变化等,模板匹配很容易就会失效。

如果你的输入图像中包含这些类型的变化因素,则你不应使用模板匹配,而应该使用专用的对象检测器,包括 HOG + 线性 SVM;Faster R-CNN;SSD;YOLO 等。

这些对象检测器以后再学。

(这里的是python代码,因为要搞到树莓派)

cv2.matchTemplate(image, templ, method, result=None, mask=None)
参数    参数解释
image    待搜索图像
templ    模板图像
method    计算匹配程度的方法
result    匹配结果
中文    英文
平方差匹配法    CV_TM_SQDIFF
归一化平方差匹配法    CV_TM_SQDIFF_NORMED
相关匹配法    CV_TM_CCORR
归一化相关匹配法    CV_TM_CCORR_NORMED
相关系数匹配法    CV_TM_CCOEFF
归一化相关系数匹配法    CV_TM_CCOEFF_NORMED
复制代码
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('change.jpg',0)
img2 = img.copy()
template = cv2.imread('change_face.png',0)
w, h = template.shape[::-1]

methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']

for meth in methods:
    img = img2.copy()
    method = eval(meth)
    res = cv2.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
        
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv2.rectangle(img,top_left, bottom_right, 255, 2)
    plt.subplot(121),plt.imshow(res,cmap = 'gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img,cmap = 'gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

复制代码

 


 

(2)图像二值化(全局阈值与自适应阈值)   :

【1】固定阈值(也是全局阈值)分割

全局阈值是一旦把阈值确定下来了,就拿这个阈值去跟图片的每一个像素灰度进行比较,以下就是设定一个阈值 127

严格意义上,这不算是二值化,因为二值化只是其中一个。

  • 示例代码以及api:
import cv2 as cv
img = cv.imread('0001.jpg', 0)
ret, th = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
cv.imshow('thresh', th)
cv.waitKey(0)
cv.destroyAllWindows()

 

 

 以下代码显示了上述各个参数不同之处:

复制代码

import cv2 as cv import matplotlib.pyplot as plt img = cv.imread('0001.jpg',0) # 应用5种不同的阈值方法 ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY) ret, th2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV) ret, th3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC) ret, th4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO) ret, th5 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO_INV) titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV'] images = [img, th1, th2, th3, th4, th5] for i in range(6): plt.subplot(2, 3, i + 1) plt.imshow(images[i], 'gray') plt.title(titles[i], fontsize=8) plt.xticks([]), plt.yticks([]) plt.show()
复制代码

 

【2】自适应阈值分割

在去除背景提取前景方面,自适应阈值函数要有效很多

关于api:

复制代码
cv.adaptiveThreshold(
    img_input, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 2)

cv2.ADAPTIVE_THRESH_MEAN_C
阈值 T(x,y) 是 (x,y) 的 blockSize×blockSize 邻域的平均值减去 C的值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C
阈值 T(x,y) 是的blockSize×blockSize邻域的加权和减去 C的值。默认的sigma(标准偏差)用于具体的blockSize。

 

cv2.THRESH_BINARY(黑白二值)
cv2.THRESH_BINARY_INV(黑白二值反转)
复制代码

 

 

原图像切割成几个n*n区域(奇数),再使用之前的高斯的模板,计算得到高斯加权值(还有一种是计算得到区域内的函数平均值),之后加上最后一个参数(偏移值)然后就得到了最终的阈值。

用这个阈值来进行比较。

疑问:既然是分割图像,如果图像大小不能完全分割是不是会再补行补列来运算?

以下是示例:(引入matplotlib就是为了看起来更直观

复制代码
import cv2 as cv 
import matplotlib.pyplot as plt
 
img = cv.imread('paojie_g.jpg',0)
 
# 固定阈值
ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
# 自适应阈值
th2 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 15, 4)
th3 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 15, 8)
 
titles = ['Original', 'Global(v = 127)', 'Adaptive Mean', 'Adaptive Gaussian']
images = [img, th1, th2, th3]
 
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()
复制代码

 


 

(4)opencv图像轮廓拟合

 


首先注意,这里的contours,hierachy 或者是ret,binary都是函数外定义

调用代码:

(001正方形框)

grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(grey,200,255,cv2.THRESH_BINARY)
contours,hierachy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
x,y,w,h= cv2.boundingRect(contours[XXX])
cv2.rectangle(img,(x,y),(x+w,y+h),(124,0,255),5)
这里是直接rectangle函数绘制矩形

 

复制代码
002:最小包围矩形框)

gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,200,255,cv2.THRESH_BINARY) 
contours, hierarchy=cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
rect = cv2.minAreaRect(contours[2])
points = cv2.boxPoints(rect)
points = np.int64(points)                         
image=cv2.drawContours(o,[points],0,(0,0,0),2)
这里只能取点,再由四个点来画类矩形的框

注:可用cv2.minAreaRect()获取点集的最小外接矩形。返回值rect内包含该矩形的中心点坐标、高度宽度及倾斜角度等信息,使用cv2.boxPoints()可获取该矩形的四个顶点坐标。
复制代码

 

复制代码
003:最小包围圆)

gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
(x,y),radius = cv2.minEnclosingCircle(contours[1])    
center = (int(x),int(y))
radius = int(radius)
cv2.circle(o,center,radius,(0,0,0),2)     
复制代码

 

复制代码
(004最小包围椭圆)

gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,200,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
ellipse = cv2.fitEllipse(contours[1])
print("ellipse=",ellipse)
cv2.ellipse(o,ellipse,(100,0,200),3)


其中elipse数据结构是 (椭圆中心坐标xy的元组,x轴y轴最长距离的元组,旋转角度)
下面有cv2绘制椭圆时的参数,其中就多了一个从绘制0到x度的限定范围(第四,五个参数)
例子:
ellipse= ((303.8422546386719, 526.1187133789062), (188.03363037109375, 188.1168975830078), 138.18173217773438)



复制代码
复制代码
(005拟合直线)

gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
rows,cols = o.shape[:2]
[vx,vy,x,y] = cv2.fitLine(contours[1], cv2.DIST_L2,0,0.01,0.01) # 返回值是共线的归一化向量,和线上一点
lefty = int((-x*vy/vx) + y)                   # 说白了就是一个方向和一个点,点斜式嘛,还啥vec4f,,讲究
righty = int(((cols-x)*vy/vx)+y)                # 计算两个点,代值计算就行
cv2.line(o,(cols-1,righty),(0,lefty),(0,255,0),2)  
cv2.imshow("result",o)
复制代码

 

 

 

import cv2
origin = cv2.imread('0001.jpg')
cv2.ellipse(origin,(500,300),(200,380),0,0,360,(0,0,0),3)
cv2.imshow("origin",origin)
cv2.waitKey(0)
cv2.destroyAllWindows

椭圆这种数据结构的验证

 

 

 

 

参数查找表:

复制代码
findContours(InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method, Point offset=Point()); 

第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;

第二个参数:contours,定义为“vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,
每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
在上述代码中,应该是把这两个放到外面定义了,这种好处就是不要另外定义了,直接传参数。 下面一个参数应该也是这样(这个理论待验证) 第三个参数:hierarchy,定义为“vector
<Vec4i> hierarchy”,先来看一下Vec4i的定义: typedef Vec<int,4> Vec4i; Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量。所以从定义上看,
hierarchy也是一个向量,
向量内每个元素保存了一个包含4个int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。
hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓
、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]
的相应位被设置为默认值-1。 第四个参数:int型的mode,定义轮廓的检索模式: 取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略 取值二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到 取值三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层 取值四:CV_RETR_TREE,检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。 第五个参数:int型的method,定义轮廓的近似方法: 取值一:CV_CHAIN_APPROX_NONE保存物体边界上所有连续的轮廓点到contours向量内 取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留 取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法 第六个参数:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值!
复制代码

 实验代码:

复制代码
import cv2
img = cv2.imread('0001.jpg')
cv2.imshow("origin",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#首先得把图像变成灰度图像
ret,binary = cv2.threshold(gray,200,255,cv2.THRESH_BINARY)
#对gray进行全局阈值操作,传入binary中
cv2.imshow("binary",binary)

contours,hierachy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)

for i in range(0,3):
    x,y,w,h= cv2.boundingRect(contours[i])
    cv2.rectangle(img,(x,y),(x+w,y+h),(124,0,255),5)
cv2.imshow('hshs',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
复制代码

 


 

 (5)图像距(几何矩、中心矩、HU 矩)

概率论还没学数学期望,暂时不学

 

(6)霍夫变换(直线与圆)

【1】关于霍夫变换
https://zhuanlan.zhihu.com/p/203292567
关于圆的霍夫变换
 https://blog.csdn.net/juzicode00/article/details/122263456

 

 大致就是换成极坐标后,xcosp + ysinp = Q

遍历p,得出各个点(x,y)处各个p所对应的Q,Q值最多的,选择,此时p与Q是确定的,直线方程也是确定的,所以就检测出了直线。

别人的解释:

  1. 通过canny等边缘检测算子找到图像中直线经过的像素点映射到ρθ坐标系(网格近似)中,获得一条曲线;
  2. 该曲线经过的像素点值+1;
  3. 重复步骤1和2,遍历整个图形;
  4. ρθ坐标系中每个元素中的数值代表图像共线的点数,数值较大的点可以作为拟合直线(ρ,θ);
  5. 霍夫逆变换求出原图直线

霍夫变换(圆)

cv2.HoughCircles(image,method,dp,minDist[,circles[,param1[,param2[,minRadius[,maxRadius]]]]])->circles

 

 

 

 

 

 

 

 


 

形态学基础:

(1)腐蚀与膨胀:

https://blog.csdn.net/poem_qianmo/article/details/23710721?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165159358616782391886114%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165159358616782391886114&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~hot_rank-6-23710721.142^v9^pc_search_result_control_group,157^v4^control&utm_term=%E5%9B%BE%E5%83%8F%E8%85%90%E8%9A%80%E5%92%8C%E8%86%A8%E8%83%80&spm=1018.2226.3001.4187

关于腐蚀与膨胀的api:

 https://blog.csdn.net/juzicode00/article/details/119580892

示例代码:

复制代码
import cv2
img = cv2.imread('0001.jpg',cv2.IMREAD_GRAYSCALE)
img_erode = img
img_dilate = img
cv2.imshow('0001',img)
kernel_1=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
kernel_2=cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
img_erode=cv2.erode(img,kernel_1,iterations=4)
img_dilate=cv2.dilate(img,kernel_2,iterations=4)
cv2.imshow('erode',img_erode)
cv2.imshow('dilate',img_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
复制代码

 

posted @   0MrMKG  阅读(91)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示