您现在的位置是:首页 >技术杂谈 >OpenCV 算法解析(一)网站首页技术杂谈

OpenCV 算法解析(一)

山居秋暝LS 2024-06-17 11:28:21
简介OpenCV 算法解析(一)

1 图像增强

1.1 含义

突出图像细节,让图像更加清晰。

1.2 方法

直方图均衡

1.2.1 直方图均衡

直方图均衡

import cv2
import numpy as np
import matplotlib.pyplot as plt


def histequal(img_gray):
   # 1 计算各个像素的频数、累积频数、归一化
   h,w = img_gray.shape
   cum_freq = np.array([(img_gray==i).sum() for i in range(255)]).cumsum()
   cum_freq = (cum_freq/cum_freq[-1]*255).astype(np.uint8)
   tmp = img_gray.copy()
   for i in range(255):
       tmp[img_gray == i] = cum_freq[i]
   return tmp


img = cv2.imread('opencv/features/cat0.jpg', 0)
out = histequal(img)
plt.subplot(121)
plt.title('org')
plt.imshow( img,cmap='gray')
plt.subplot(122)
plt.title('histequal')
plt.imshow( out,cmap='gray')
plt.show()

在这里插入图片描述

1.2.2 gamma变换

import cv2
import numpy as np
import matplotlib.pyplot as plt

def gamma(img,c=2,r=2):
    return np.array(c*img**r,dtype=np.uint8).clip(0,255)


img = cv2.imread('/Users/liushuang/Desktop/LearnGit/项目实战/鱼苗检测/yolov5-master/opencv/features/cat.jpg')
out = gamma(img)
plt.subplot(121)
plt.title('org')
plt.imshow( img,cmap='gray')
plt.subplot(122)
plt.title('gamma')
plt.imshow( out,cmap='gray')
plt.show()

在这里插入图片描述

2 除噪

2.1 含义

除去图片上的噪声

2.2 方法

空间滤波法(均值滤波、高斯滤波、中值滤波、双边滤波),变换滤波(傅立叶,小波变换)、形态学等

2.2.1 高斯滤波

高斯滤波
高斯滤波适合处理呈正态分布的噪声。滤波器的特点是权值成正态分布。方差越大,滤波效果越明显;反之,效果越差。

import cv2
import numpy as np
import matplotlib.pyplot as plt


def guassian_filter(img, k_size=3, sigma=2):
    # 获取通道
    if len(img.shape) == 3:
        h, w, c = img.shape
    else:
        img = np.expand_dims(img, axis=-1)
        h, w, c = img.shape

    # img padiing
    pad = (k_size - 1) // 2
    out_put = np.zeros((h + pad * 2, w + pad * 2,3), dtype=np.float32)
    out_put[pad:pad + h, pad:pad + w] = img.copy().astype(np.float32)

    # generate kernel
    k = np.zeros((k_size, k_size), dtype = np.float32)

    for i in range(-pad, k_size - pad):
        for j in range(-pad, k_size - pad):
            k[j + pad, i + pad] = np.exp(-(i ** 2 + j ** 2) / (2 * sigma ** 2))
    k /= (2 * np.pi * sigma ** 2)
    k /= k.sum()
    tmp = out_put.copy()

    # Gaussian filter
    for i in range(h):
        for j in range(w):
            for cc in range(c):
                out_put[pad + i, pad + j, cc] = np.sum(k * tmp[i:i + k_size, j:j + k_size, cc])
    out_put = np.clip(out_put, 0, 255)

    return out_put[pad:pad + h, pad:pad + w].astype(np.uint8)


#
img = cv2.imread('opencv/features/dogGauss.jpeg')
out = guassian_filter(img, k_size=3, sigma=2)
plt.subplot(121)
plt.title('org')
plt.imshow( img[...,::-1])
plt.subplot(122)
plt.title('out')
plt.imshow( out[...,::-1])
plt.show()

    
# sigma = 1 ,高斯核
'''
array([[0.07511362, 0.12384141, 0.07511362],
       [0.12384141, 0.20417996, 0.12384141],
       [0.07511362, 0.12384141, 0.07511362]], dtype=float32)

# sigma = 3
array([[0.10699731, 0.11310981, 0.10699731],
       [0.11310981, 0.11957153, 0.11310981],
       [0.10699731, 0.11310981, 0.10699731]], dtype=float32)
'''

在这里插入图片描述

2.2.2 均值滤波

### 2.2.2 mean+filter
import cv2
import numpy as np
import matplotlib.pyplot as plt

def mean_filter(img, k_size=3):
    # shape
    if len(img.shape) != 3:
        img = img[..., None]
    h, w, c = img.shape
    # 1 kernel
    k = np.ones((k_size, k_size), np.float32) / (k_size * k_size)
    # 2 out_Put
    pad = (k_size - 1) // 2
    out_put = np.zeros((h + 2*pad, w + 2*pad, c), np.float32)
    out_put[pad:pad + h, pad:pad + w] = img.copy().astype(np.float32)
    # 3 filte
    tmp = out_put.copy()
    for i in range(h):
        for j in range(w):
            for cc in range(c):
                out_put[pad + i:, pad + j, cc] = (tmp[i:i + k_size, j:j + k_size, cc] * k).sum()

    out_put = np.clip(out_put, 0, 255)

    return out_put[pad:pad + h, pad:pad + w].astype(np.uint8)


# filte

img = cv2.imread('opencv/features/dogGauss.jpeg')
out = mean_filter(img, k_size=3)
plt.subplot(121)
plt.title('org')
plt.imshow(img[..., ::-1])
plt.subplot(122)
plt.title('out_mean_filter')
plt.imshow(out[..., ::-1])
plt.show()

在这里插入图片描述

2.2.3 中值滤波

取窗口的中位数作为中心点的值,如果效果不好,可以增大核的尺寸,或者多循环几次。

import cv2
import numpy as np
import matplotlib.pyplot as plt


def median_filter(img, k_size=10):
    # shape
    if len(img.shape) != 3:
        img = img[..., None]
    h, w, c = img.shape

    # 2 out_Put
    pad = (k_size - 1) // 2
    out_put = np.ones((h + 2 * pad, w + 2 * pad, c), np.float32) * (-1)
    out_put[pad:pad + h, pad:pad + w] = img.copy().astype(np.float32)
    # 3 filte
    tmp = out_put.copy()
    for i in range(h):
        for j in range(w):
            for cc in range(c):
                t = tmp[i:i + k_size, j:j + k_size, cc]
                out_put[pad + i:, pad + j, cc] = np.median(t[t > 0])

    return out_put[pad:pad + h, pad:pad + w].astype(np.uint8)


# filte

img = cv2.imread('opencv/features/letteropen.png')
out = median_filter(img, k_size=20)
plt.subplot(121)
plt.title('org')
plt.imshow(img[..., ::-1])
plt.subplot(122)
plt.title('median_filter')
plt.imshow(out[..., ::-1])
plt.show()

在这里插入图片描述

3 边缘检测

3.1 canny

canny 边缘检测流程

  1. 平滑处理
  2. 梯度检测
  3. 非极大值抑制
  4. 滞后阈值处理

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

def canny(img):
    # 1. 平滑
    img_blur = cv.GaussianBlur(img, (5, 5), 2)

    # 2. 梯度
    gradx = cv.Sobel(img_blur, cv.CV_64F, 1, 0)  # x
    grady = cv.Sobel(img_blur, cv.CV_64F, 0, 1)  # y
    R = np.abs(gradx) + np.abs(grady)
    T = np.arctan(grady / (gradx + 1e-3))

    # 3. 非极大值抑制,细化边缘
    h, w = R.shape
    img_thin = np.zeros_like(R)

    for i in range(1, h - 1):
        for j in range(1, w - 1):
            theta = T[i, j]
            if -np.pi / 8 <= theta < np.pi / 8:        #  (-22,22)
                if R[i, j] == max([R[i, j], R[i, j - 1], R[i, j + 1]]):            #  上下
                    img_thin[i, j] = R[i, j]
            elif -3 * np.pi / 8 <= theta < -np.pi / 8:  #  (-66,-22)
                if R[i, j] == max([R[i, j], R[i - 1, j + 1], R[i + 1, j - 1]]):  #  斜线
                    img_thin[i, j] = R[i, j]
            elif np.pi / 8 <= theta < 3 * np.pi / 8:    #  (22,66)
                if R[i, j] == max([R[i, j], R[i - 1, j - 1], R[i + 1, j + 1]]):  # 反斜线
                    img_thin[i, j] = R[i, j]
            else:                                       #  (66,110)
                if R[i, j] == max([R[i, j], R[i - 1, j], R[i + 1, j]]):            # 左右
                    img_thin[i, j] = R[i, j]

    # 4 双阈值抑制
    th1 = 5
    th2 = 30
    maxv = 255
    img_edge = np.zeros_like(img_thin)
    h, w = img_thin.shape
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            if img_thin[i, j] >= th2:
                img_edge[i, j] = maxv
            elif img_thin[i, j] > th1:
                around = img_thin[i - 1:i + 2, j - 1:j + 2]
                if around.max() >= th2:
                    img_edge[i, j] = maxv
    return img_edge

img = cv2.imread('opencv/features/letteropen.png', 0)
out = canny(img)
plt.subplot(121)
plt.title('org')
plt.imshow( img,cmap='gray')
plt.subplot(122)
plt.title('canny')
plt.imshow( out,cmap='gray')
plt.show()

在这里插入图片描述

4 HOG特征提取

4.1 含义

通过提取图像局部区域梯度直方图构成特征,进而获取整个图像的特征。HOG对几何和光学形变都能保持不变形。通过局部归一化,忽略细节的变化,提取共哦那个特性。

4.2 流程

img --> cells,blocks --> 计算每个cell的梯度直方图

4.3 案例

6 两个比赛

6.1 三个功能整合

6.2 目标检测

6.3 yolov5代码详解

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。