图像处理

1. 图像阈值

ret, dst = cv2.threshold(src, thresh, maxval, type)

  • src: 输入图,只能输入单通道图像,通常来说为灰度图

  • dst: 输出图

  • thresh: 阈值

  • maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值

  • type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV

  • cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0

  • cv2.THRESH_BINARY_INV THRESH_BINARY的反转

  • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变

  • cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0

  • cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转

2.图像平滑:滤波-filter

均值滤波:取卷积核为n阶全一矩阵,计算中心点卷积核范围内的均值

方框滤波:取卷积核为n阶全一矩阵,计算中心点卷积核范围内的均值,归一化可选:true则等于均值滤波,false则不取均值,超过255取255

高斯滤波:高斯分布即正态分布,卷积核内距离中心点越大权重越大,高斯分布标准差可选

中值滤波:取中心点卷积核内中值

3. 形态学

腐蚀:多用于二值图像,卷积核内取最大值:0--黑色|255--白色

膨胀:多用于二值图像,卷积核内取最小值

OpenCV---膨胀与腐蚀 - 山上有风景 - 博客园 (cnblogs.com)

腐蚀与膨胀也可以对彩色图进行处理,但是效果不怎么样,一般不用

 上述的模板或者成卷积核封装入opencv中的腐蚀和膨胀操作,如果想自己操作的话可以利用opencv中的getStructuringElement函数来实现,其内部是生成一个mat(指定的形状和size)

开运算:先腐蚀再膨胀

闭运算:先膨胀再腐蚀

梯度运算:膨胀-腐蚀,抽象的“梯度”

高帽:显示毛刺,原图-开运算

黑帽:显示瑕疵,闭运算-原图

imageH1 = numpy.hstack((img, errosion, dilate, openOp))
imageH2 = numpy.hstack((closeOp, grad, tophat, blackHat))
image = numpy.vstack((imageH1, imageH2))
image = cv2.resize(image, (0, 0), fx=0.3, fy=0.3)
_cvShow("image", image)

4. 图像梯度

Sobel算子:dx|dy,卷积核--dx_A = [[-1,0,1], [-2,0,2], [-1,0,1]],dy_B = A^T

Scharr算子:dx|dy,放大差异

Laplacian算子:无dx||dy,对变化更敏感,L = [[0,1,0],[1,-4,1],[0,1,0]]

 

5. Canny边缘检测

 步骤

  • 1) 使用高斯滤波器,以平滑图像,滤除噪声。

  • 2) 计算图像中每个像素点的梯度强度和方向。

  • 3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。

  • 4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。

  • 5) 通过抑制孤立的弱边缘最终完成边缘检测。

(图像噪点严重可先做一次中值滤波,再进行Canny边缘检测)

6. 图像金字塔

高斯金字塔:向下采样-高斯内核卷积;向上采样:扩充矩阵+高斯内核卷积

拉普拉斯金字塔:原图-up_down

原来图片是这样压缩的_哔哩哔哩_bilibili

7. 图像轮廓:多用二值数据(二值 != 灰度图)

cv2.findContours(img,mode,method)

mode:轮廓检索模式

  • RETR_EXTERNAL :只检索最外面的轮廓;
  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
  • RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
  • RETR_TREE:最常用,检索所有的轮廓,并重构嵌套轮廓的整个层次;

method:轮廓逼近方法(常用)

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

# 轮廓检测多用二值
import cv2
import numpy

img_ori = cv2.imread("../pics/contours.png")
img = cv2.cvtColor(img_ori, cv2.COLOR_BGR2GRAY)  # 注意转换灰度图和读取灰度图的参数不一样
ret, thresh = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY)  # 127为阈值,255为maxVal


def _show(str, img, size):
    cv2.imshow(str, cv2.resize(img, (0, 0), fx=size, fy=size))
    cv2.moveWindow(str, 500, 200)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def _drawContours(img, contours, which):
    draw_img = img.copy()  # 直接=赋值相当于指针,还是会被修改
    res = cv2.drawContours(draw_img, contours, which, (0, 0, 255), 2)  # -1/0
    # draw_img---在哪里画,这个图像是否灰度无所谓,(个人)甚至不是原图也行,就是没什么意义
    # 这个函数会直接修改原图,故先复制一下,防止后续没法用了
    # -1表示画出所有轮廓
    # 0,0,255---bgr,这里是使用红色来画,简单来讲就是用什么颜色取描绘轮廓
    # 2---线条宽度
    return res


binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# binary是二值图像,contours存储轮廓信息,hierarchy是层次数据(暂时不用)
_drawContours(img_ori, contours, -1)

images = [img, img, img, img, img]

for i in range(5):
    images[i] = _drawContours(img_ori, contours, i - 1)

h1 = numpy.hstack((img_ori, images[0], images[1]))
h2 = numpy.hstack((images[2], images[3], images[4]))
res = numpy.vstack((h1, h2))
_show("contours", res, 0.5)

轮廓特征

cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt,True)

轮廓近似:以直代曲

# 轮廓近似:以直代曲
def _imiContours(contours, lenRate, i):
    cnt = contours[i]
    epsilon = lenRate * cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    # cnt:轮廓
    # epsilon:阈值,超过这个值由多条直线代替曲线
    # true:闭合
    return _drawContours(img_ori, [approx], -1)


imis = [img_ori, _drawContours(img_ori, contours, 0), _imiContours(contours, 0.1, 0), _imiContours(contours, 0.01, 0)]

h1 = numpy.hstack((imis[0], imis[1]))
h2 = numpy.hstack((imis[2], imis[3]))
res = numpy.vstack((h1, h2))

_show("res", res, 1)

边界图形

cnt = contours[0]
# 外接矩形
x, y, w, h = cv2.boundingRect(cnt)
img = img_ori.copy()
rec = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
# img_ori,如果是在灰度图上标识只能用白色((255,255,255))来画线,否则看不到
# 外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
img = img_ori.copy()
circle = cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 0), 2)  # x,y,radius只能是整数

res = numpy.hstack((img_ori, rec, circle))
_show("res", res, 1)

8. 傅里叶变换

傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎 (zhihu.com)

这个写得非常好,有机会要多读几遍

 9. 模板匹配

# 模板匹配:类比串的模式匹配
# opencv提供了各种函数来计算像素点之间的关系,如方差、相关系数等
import cv2
import matplotlib.pyplot as plt
# 流程:
# 1. 读入图片+模板
# 2. 依次(每像素)比较模板和图片,计算模板和图片比较区域像素值的差异并记录,返回结果应该是[picw-temw+1]*[pich-temh+1]的ndarray
# 3. 遍历返回结果得到最有可能的点及其坐标(点在返回结果中的坐标值就是点在图像中的坐标值)
# 另,应该明白,如果将返回的数据画出,则图中最量或最暗的点(值越大或者越小)就是相似度最高的部分所在位置
import numpy

img = cv2.imread("../pics/lena.jpg")
template = cv2.imread("../pics/face.jpg")
h, w = template.shape[:2]  # :2---取横坐标全部,纵坐标前两列,如果是2*2的矩阵,则w,h就分别为2*1的矩阵了
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']


# 图像匹配的所有参数计算方法,应用归一化操作的方法通常表现更好


def _show(str, img, size):
    cv2.imshow(str, cv2.resize(img, (0, 0), fx=size, fy=size))
    cv2.moveWindow(str, 500, 200)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


temp = numpy.hstack((img, img))
images = [temp, temp, temp, temp, temp, temp]

# 设置图像尺寸
plt.figure(figsize=(20,16), dpi=300)

for meth, i in zip(methods, range(len(methods))):
    img2 = img.copy()
    b, g, r = cv2.split(img2)
    img2 = cv2.merge((r, g, b))

    # 匹配方法的真值
    method = eval(meth)  # 如eval('1+1') = 2,而这里cv2.TM_CCOEFF是类似枚举类型,具有具体的整数值的,这样可以直接得到
    print(method)
    res = cv2.matchTemplate(img, template, method)  # 这里method不能直接输入字符串
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # method下pic和temp之间的相似关系值:min, max;以及位置,显然min_loc和max_loc都是二维的

    # 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
    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(img2, top_left, bottom_right, (0, 0, 255), 2)

    plt.subplot(2, 6, 2 * i + 1)
    plt.imshow(res, cmap='gray')
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴

    plt.subplot(2, 6, 2 * i + 2)
    plt.imshow(img2, cmap='gray')
    plt.xticks([]), plt.yticks([])

plt.show()

 匹配多个对象

# 多对象匹配:使用相关系数计算:越接近于1就越像
img_rgb = cv2.imread('../pics/mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('../pics/mario_coin.jpg', 0)
h, w = template.shape[:2]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = numpy.where(res >= threshold)
for pt in zip(*loc[::-1]):  # *号表示可选参数
    bottom_right = (pt[0] + w, pt[1] + h)
    cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 1)

_show("res", img_rgb, 1)

 10. 直方图

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("../pics/lena.jpg")  # 0---gray
b, g, r = cv2.split(img)
img2 = cv2.merge((r, g, b))
imgGray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist(imgGray, [0], None, [256], [0, 256])
color = ('b', 'g', 'r')

plt.figure(dpi=150)
grid = plt.GridSpec(2, 6)

plt.subplot(grid[0, 0:2])
plt.imshow(img2)

plt.subplot(grid[0, 3:5])
plt.imshow(imgGray, cmap='gray')

plt.subplot(grid[1, 1:5])
plt.hist(imgGray.ravel(), 256, color='black')
for i, col in enumerate(color):
    histr = cv2.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(histr, color=col)
    plt.xlim([0, 256])

plt.show()

 

LR / ACR曲线工具原理。_哔哩哔哩_bilibili

 

posted @ 2022-01-15 23:00  YIYUYI  阅读(63)  评论(0编辑  收藏  举报