数字图像处理集成器(灰度操作,伽马变换,HSV,滤波,高斯,算子)

2 篇文章 0 订阅
1 篇文章 0 订阅

引言

数字图像处理集成器GUI可视化界面(灰度值HSV,RGB,高斯低通高通,低通滤波频域空间域一二阶算子综合)
文件中包含两种代码,第一种是可视化界面的直接实现与代码综合,另一个单纯的算法函数实现)
如果需要源码可以选择下载,也可以一步步学习复制
路标指引处理器下载路径

  1. 灰度值转化,HSV三通道便函,RGB拆分对比
  2. 灰度直方图对比均衡化归一化,伽马变换矩阵变换操作节约时间
  3. 空间域低通高通中值滤波,一共四种不同的操作
  4. 频域上高斯低通和高通滤波
  5. 一二级算子一共四种对比效果
    所有代码都是自己的手动实现,并没有调用opencv库,适合初学者的学习和调用
    下文分为六种模块,包括原理讲解和代码实现。

HSV and RGB 模式

原理讲解

色彩分析是数字图像处理过程中最基本的一种分析方法,目的是使数字图像获得更好的识别效果
RGB颜色模型称为与设备相关的颜色模型,RGB颜色模型所覆盖的颜色域取决于显示设备荧光点的颜色特性,与硬件相关。
• 使用最多,最熟悉的颜色模型。它采用三维直角坐标系。红、绿、蓝原色是加性原色,各个原色混合在一起可以产生复合色。
• RGB颜色模型通常采用单位立方体来表示。在正方体的主对角线上,各原色的强度相等,产生由暗到明的白色,也就是不同的灰度值。(0,0,0)为黑色,(1,1,1)为白色。正方体的其他六个角点分别为红、黄、绿、青、蓝和品红。

HSI模型的建立基于两个重要的事实:

① I分量与图像的彩色信息无关;② H和S分量与人感受颜色的方式是紧密相联的。

• HSI颜色模型的双圆锥表示
– I是强度轴
– 色调H的角度范围为[0,2π],其中,纯红色的角度为0,纯绿色的角度为2π/3,纯蓝色的角度为4π/3。
– 饱和度S是颜色空间任一点距I轴的距离。
• 注意: 当强度I=0时,色调H、饱和度S无定义;当S=0时,色调H无定义。
在这里插入图片描述
在这里插入图片描述

HSV代码实现

def rgb_to_hsv(rgb_image):
    r, g, b = rgb_image[:, :, 0] / 255.0, rgb_image[:, :, 1] / 255.0, rgb_image[:, :, 2] / 255.0
    #最大化最小化
    max_val = np.maximum(np.maximum(r, g), b)
    min_val = np.minimum(np.minimum(r, g), b)
    v = max_val
    s = np.where(max_val != 0, (max_val - min_val) / max_val, 0)
    factor = np.where(max_val-min_val>0,max_val-min_val,0)
    h = np.zeros_like(factor)
    h[max_val == r] = 60 * ((g[max_val == r] - b[max_val == r]) / factor[max_val == r] % 6)
    h[max_val == g] = 60 * ((b[max_val == g] - r[max_val == g]) / factor[max_val == g] + 2)
    h[max_val == b] = 60 * ((r[max_val == b] - g[max_val == b]) / factor[max_val == b] + 4)
    h = np.where(h < 0, h + 360, h)/2
    # 色调H参数表示色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,取值范围为0°~360°。若从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°;
    # 饱和度S:取值范围为0.0~1.0;
    # 亮度V:取值范围为0.0(黑色)~1.0(白色)。
    # 矩阵255转编码
    h = h.astype(np.uint8)
    s = (s * 255).astype(np.uint8)
    v = (v * 255).astype(np.uint8)
    hsv_image = np.stack((h, s, v), axis=-1)
    fig, axs = plt.subplots(2, 2, figsize=(10, 10))
    axs[0, 0].imshow(hsv_image)
    axs[0, 0].set_title('HSV Image')
    axs[0, 1].imshow(h)
    axs[0, 1].set_title('H Channel')
    axs[1, 0].imshow(s)
    axs[1, 0].set_title('S Channel')
    axs[1, 1].imshow(v)
    axs[1, 1].set_title('V Channel')
    # axs[0, 0].imshow(hsv_image, cmap=plt.get_cmap('gray'))
    # axs[0, 0].set_title('HSV Image')
    # axs[0, 1].imshow(h, cmap=plt.get_cmap('gray'))
    # axs[0, 1].set_title('H Channel')
    # axs[1, 0].imshow(s, cmap=plt.get_cmap('gray'))
    # axs[1, 0].set_title('S Channel')
    # axs[1, 1].imshow(v, cmap=plt.get_cmap('gray'))
    # axs[1, 1].set_title('V Channel')
    plt.tight_layout()
    zipper = "result_folder"
    if not os.path.exists(zipper):
        os.makedirs(zipper)
    result_file_path = os.path.join(zipper, "hsv.jpg")
    plt.savefig(result_file_path)

灰度化处理小技巧

使用矩阵化的操作可以使算法的执行速度加快不止一个数量级

def rgb2gray(rgb):
    return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])

灰度直方图以及预处理化

把白色与黑色之间按对数关系分为若干等级,称为灰度。灰度分为256阶。

任何颜色都有红、绿、蓝三原色组成,即三通道,而灰度图只有一个通道,他有256个灰度等级,255代表全白,0表示全黑。灰度图像是指用灰度表示的图像,即一个像元用1个Byte(bits)表示辐射值。

  1. 浮点法:Gray=R0.3+G0.59+B*0.11

  2. 整数法:Gray=(R30+G59+B*11)/100

  3. 移位法:Gray =(R77+G151+B*28)>>8;

  4. 平均值法:Gray=(R+G+B)/3;

  5. 仅取绿色:Gray=G;

图像处理的意义

直方图均衡化(Histogram Equalization)又称直方图平坦化,它的主要目标是将输入图像的像素值分布重新映射,以使其更均匀地分布在整个像素值范围内。这有助于使图像的亮度范围更广,增加对比度,并使细节更加突出。
原来直方图中间的峰顶部分对比度得到增强,而两侧的谷底部分对比度降低,输出图像的直方图是一个较平的分段直方图,如果输出数据分段值较小的话,会产生粗略分类的视觉效果。
在这里插入图片描述

伽马变换

在图像处理中,将漂白(相机过曝)的图片或者过暗(曝光不足)的图片进行修正。基本公式为:
在这里插入图片描述
详解过程
在这里插入图片描述
gamma值小于1时,会拉伸图像中灰度较低的区域,同时会压缩灰度级较高的部分。

gamma值大于1时,会拉伸图像中灰度级较高的区域,同时会压缩灰度级较低的部分。

也就是图像变亮或者是变暗的对比效果。

均衡化与归一化原理

把一个已知灰度概率密度分布的图像经过一种灰度变换(变换函数的离散形式如图所示),使之演变为一幅具有均匀灰度概率密度分布(且尽量占满全部灰度)的新图像,以此增加了像素灰度值的动态范围从而达到增强图像整体对比度的效果。

均衡化归一化与伽马变换代码实现

def get_histogram(img, *, Normalized=False):
        img = img[:, :, 0]
        size_h, size_w = img.shape
        logging.info(f' size_h :{size_h} size_w:{size_w} MN:{size_w * size_h}')
        hist = defaultdict(lambda: 0)
        for i in range(size_h):
            for j in range(size_w):
                hist[img[i, j]] += 1
        # 优化
        if Normalized == True:
            sum = 0
            MN = size_h * size_w
            for pixel_value in hist:  # Key 迭代
                hist[pixel_value] = hist[pixel_value] / MN
                sum += hist[pixel_value]
            logging.info(f'归一化后加和为:{sum}')
            del sum
        return hist
def equalization(img):
    size_h, size_w, size_c = img.shape
    hist = get_histogram(img)
    MN = size_h * size_w
    new_hist = defaultdict(lambda: 0)
    for i in range(0, 256):
        for pixel in range(i + 1):
            new_hist[i] += hist[pixel]
        new_hist[i] = new_hist[i] * 255 / MN
    for key in new_hist:
        new_hist[key] = round(new_hist[key])
    new_img = img.copy()
    for i in range(new_img.shape[0]):
        for j in range(new_img.shape[1]):
            new_img[i, j] = new_hist[new_img[i, j, 0]]
    return new_img
def convert_to_gray(image):
    gray_image = rgb2gray(image)
    fig, axs = plt.subplots(2, 2, figsize=(10, 10))
    axs[0,0].imshow(gray_image,cmap=plt.get_cmap('gray'))
    axs[0,0].set_title("Gray Image")
    axs[0,1].hist(gray_image.ravel(), 256, color='gray')
    axs[0,1].set_title("Gray Image Histogram")
    equalizedimg=equalization(image)
    axs[1,0].imshow(equalizedimg)
    axs[1,0].set_title("Histogram_equalization Image")
    axs[1,1].hist(equalizedimg.ravel(),256,color='gray')
    axs[1,1].set_title("Histogram_equalization Image of Histogram")
    plt.tight_layout()
    zipper = "result_folder"
    result_file_path = os.path.join(zipper, "gray.jpg")
    plt.savefig(result_file_path)

def GammaTranform(c,gamma,image):    # 三通道
    h,w,d = image.shape[0],image.shape[1],image.shape[2]
    new_img = np.zeros((h,w,d),dtype=np.float32)
    for i in range(h):
        for j in range(w):
            new_img[i,j,0] = c*math.pow(image[i, j, 0], gamma)
            new_img[i,j,1] = c*math.pow(image[i, j, 1], gamma)
            new_img[i,j,2] = c*math.pow(image[i, j, 2], gamma)
    cv.normalize(new_img,new_img,0,255,cv.NORM_MINMAX)
    new_img = cv.convertScaleAbs(new_img)
    return new_img

低通滤波与高通滤波在空间域上变换

不同图像具有不同的灰度分布,可以用图像的灰度分布作为表征图像的一种方式,该方式被称为空间域。空间域滤波是指在图像空间中借助模板对图像领域进行操作,处理图像每一个像素值。主要分为线性滤波和非线性滤波两类,根据功能可分为平滑滤波器和锐化滤波器,即低通滤波和高通滤波。滤波,实际上就是信号的处理,而图像本身可以看作是一个二维信号,其中像素点灰度的高低代表信号的强弱,对应高低频,具体如下:
高频部分为图像灰度变化强烈的点,一般是轮廓或者是噪声。
低频部分为图像中平坦的、灰度变化不大的点,是图像中的大部分区域。
空间域滤波的适用情况:
(1)实时处理:空间域滤波通常在图像处理的实时应用中使用,因为它不
需要对图像进行额外的转换(如从空间域到频域),可以直接在像素级别操作。
(2)简单噪声抑制:对于简单的噪声抑制任务,如去除随机噪声,空间域
的低通滤波器(如均值滤波或中值滤波)可以提供快速且有效的解决方案。
(3)边缘保护:在需要保护图像边缘的同时进行平滑处理时,空间域的低
通滤波器(如高斯滤波)可以提供较好的边缘保护效果。
(4)特定形状的滤波器:如果需要应用特定形状的滤波器(如梯度算子),
直接在空间域进行会更直观。

平滑滤波

平滑滤波包括:均值滤波、加权均值滤波、阈值平均滤波、中值滤波、高斯滤波等,应用时他们仅是卷积核之间的不同。

平滑滤波用于模糊处理和降低噪声。模糊处理常用于预处理任务中,如在目标提取之前去除图像中的一些琐碎细节,以及桥接直线或曲线的缝隙。通过线性或非线性平滑滤波也可降低噪声。

均值滤波

均值滤波(normalized box filter)就是用其像素点周围像素的平均值代替元像素值,在滤除噪声的同时也会滤掉图像的边缘信息的方法。

但均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。特别是椒盐噪声。

高斯滤波器

高斯滤波是一种线性平滑滤波器,对于服从正态分布的噪声有很好的抑制作用。在实际场景中,我们通常会假定图像包含的噪声为高斯白噪声,所以在许多实际应用的预处理部分,都会采用高斯滤波抑制噪声,如传统车牌识别等。

高斯滤波和均值滤波一样,都是利用一个掩膜和图像进行卷积求解。不同之处在于:均值滤波器的模板系数都是相同的为1,而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小(服从二维高斯分布),从而确保中心点看起来更接近与它距离更近的点。所以,高斯滤波器相比于均值滤波器对图像个模糊程度较小,更能够保持图像的整体细节。

中值滤波

统计排序滤波器,非线性滤波器。如果不在边缘区域,图像的数据是平缓的,没有太大的差值。因此,一个噪声点的值要么过大,要么过小。比如下图,左图是没有处理的原图,90在该区域由为突出,通过对33的9个数据进行排序,将中间值27重新填入,即滤波完成,原本的噪声点被去掉,该区域恢复平缓。同理,在边缘区域中,对于边界来说,高频不会影响,而过低数值将会突出,中值的选择将不会受到影响,除非33的整块区域都被污染,这时我们可以考虑更大的核来处理。

空间域代码滤波实现

def get_median(data):
    data.sort()
    half = len(data) // 2
    return data[half]
def midlow_pass_filter(image,size):
    data = []
    sizepart = int(size / 2)
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            for ii in range(size):
                for jj in range(size):
                    # 首先判断所以是否超出范围,也可以事先对图像进行零填充
                    if (i + ii - sizepart) < 0 or (i + ii - sizepart) >= image.shape[0]:
                        pass
                    elif (j + jj - sizepart) < 0 or (j + jj - sizepart) >= image.shape[1]:
                        pass
                    else:
                        data.append(image[i + ii - sizepart][j + jj - sizepart])
            # 取每个区域内的中位数
            image[i][j] = int(get_median(data))
            data = []
    return image
def avelow_filter(image, size):
    input_image_cp = np.copy(image)
    filter_template = np.ones((size, size))
    pad_num = int((size - 1) / 2)  # 填充
    input_image_cp = np.pad(input_image_cp, (pad_num, pad_num), mode="constant", constant_values=0)
    m, n = input_image_cp.shape
    output_image = np.copy(input_image_cp)
    # 空间滤波
    for i in range(pad_num, m - pad_num):
        for j in range(pad_num, n - pad_num):
            output_image[i, j] = np.sum(filter_template * input_image_cp[i - pad_num:i + pad_num + 1, j - pad_num:j + pad_num + 1]) / (size ** 2)
    output_image = output_image[pad_num:m - pad_num, pad_num:n - pad_num]
    return output_image
def low_pass_filter(size, cutoff, n=1):
    rows, cols = size
    crow, ccol = rows // 2, cols // 2
    x = np.linspace(-ccol, ccol, cols)
    y = np.linspace(-crow, crow, rows)
    xv, yv = np.meshgrid(x, y)
    distance = np.sqrt(xv ** 2 + yv ** 2)
    filter = 1 / (1 + (distance / cutoff) ** (2 * n))
    return filter
def low_filter(image, cutoff, n=1):
    gray = rgb2gray(image)
    rows, cols = gray.shape
    fft_image = fftshift(fft2(gray))
    lp_filter = low_pass_filter(fft_image.shape, cutoff, n)
    fft_image_filtered = fft_image * lp_filter
    ifft_image = ifft2(ifftshift(fft_image_filtered))
    filtered_image = np.abs(ifft_image)
    return filtered_image
def filter2D(image, kernel):
    height, width, channels = image.shape
    output_image = np.zeros((height, width, channels), dtype=np.uint8)
    kernel_height, kernel_width = kernel.shape
    padding_height = kernel_height // 2
    padding_width = kernel_width // 2
    padded_image = cv.copyMakeBorder(image, padding_height, padding_height, padding_width, padding_width, cv.BORDER_CONSTANT, value=0)
    for y in range(height):
        for x in range(width):
            roi = padded_image[y:y+kernel_height, x:x+kernel_width]
            filtered_value = np.sum(roi * kernel)
            output_image[y, x] = filtered_value
    return output_image
def lowkernel():
    return 5
def setkernel():
    kernel = np.array([[0, -1, 0],
                       [-1, 5, -1],
                       [0, -1, 0]])
    return kernel
def PFTdomain(image):
    fig, axs = plt.subplots(1, 3, figsize=(12, 4))
    image_rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
    axs[0].imshow(image_rgb)
    axs[0].set_title('Original Image ')
    lkernel=lowkernel()
    # blurred_image = low_filter(image, lkernel)
    blurred_image=low_filter(image,lkernel,1)
    filtered_image = filter2D(image, setkernel())
    axs[1].imshow(blurred_image,cmap='gray')
    axs[1].set_title('Low Pass Filtered Image')
    axs[2].imshow(filtered_image,cmap='gray')
    axs[2].set_title('High Pass Filtered Image')
    plt.tight_layout()
    zipper = "result_folder"
    result_file_path = os.path.join(zipper, "PFT.jpg")
    plt.savefig(result_file_path)

高斯低通高通在频域上变换

频率域高斯低通滤波的主要目的是平滑图像并降低图像中的高频成分,从而实现去除噪声以及平滑处理两个目标。对于去除噪声来说,高斯低通滤波可以减少图像中的高频噪声,改善图像的质量和视觉效果。噪声通常表现为图像中的细小颗粒或杂点,通过低通滤波可以降低这些噪声的影响,使图像更加清晰,可以应用于各种地方来进行图像改进。对于平滑处理图像来说,高斯低通滤波在一定程度上模糊图像,使图像变得更加平滑,这可以消除或减轻图像中的细节和纹理,从而起到平滑图像的作用。例如,在人脸识别中,可以使用高斯低通滤波来平滑图像并减少噪声,以便更好地提取人脸特征。
频率域的高通图像滤波具有重大的意义,例如在图像增强方面,通过增强图像中的细节和纹理,高通滤波可以使图像更加清晰、饱满和富有层次感,在一些特定的图像处理任务重具有重要意义,例如,在图像增强中,可以使用高通滤波突出图像中的细节和边缘,使其更加鲜明,并且在图像分析中,高通滤波可以用于检测图像中的边缘、纹理和形状等特征。高通滤波也常用语图像处理的后期处理步骤,通过增强图像的细节和纹理,可以改善图像的质量和视觉效果,使其更加吸引人,并且也为图像处理等方面的技术提供支持,可以增强语义分割以及实例分割的准确度。因此图像的频率域滤波在图像处理以及深度学习方面都有重大的意义。

执行原理

先需要对输入图片进行傅里叶变换,法国数学家傅里叶在《热分析理论》中指出:任何周期函数都可以分解为不同频率的正弦或余弦级数的形式,即傅里叶级数,一维傅里叶变换公式如公式(1)所示,二位傅里叶变换公式如公式(2)所示。该方法从本质上完成了空间信息到频域信息的变换,通过变换将空间域信号处理问题转换成频域信号处理问题,傅里叶变换可以将任何周期函数,分解为不同频率的信号成分。频域变换为信号处理提供了不同的思路,有时在空间域无法处理的问题,通过频域变换却非常容易。为了更加有效的对数字图像进行处理,常常需要将原始图像,以某种方式变换到另一个空间,并利用图像在变换空间中特有的性质,对图像信息进行加工,然后再转换回图像空间,就可以得到所需的效果。同时,傅里叶变化有很多优良性质,二维离散傅里叶变换(DFT),可视为由沿着x、y方向的两个一维傅里叶变换所构成。这一性质可有效降低二维傅里叶变换的计算复杂性,并且二维傅里叶变化还具有平移性质:f(x,y)在空间平移了,相当于把傅里叶变换与一个指数相乘,相当于平移其傅里叶变换。傅里叶变化还具有旋转特性,对f(x,y)旋转一定角度,相当于将其傅里叶变换F(u,v)旋转一定角度。

傅里叶变换

在这里插入图片描述
在这里插入图片描述

公式讲解

高通滤波器为:让高频信息通过,过滤低频信息;低通滤波相反。

理想的低通滤波器模板为:
在这里插入图片描述
Butterworth低通滤波器函数为:
在这里插入图片描述
Guassian低通滤波器函数为:
在这里插入图片描述

高斯低通高通滤波代码实现

def GaussianLowFilter(image,d,s1):
    # 截止频率
    f = np.fft.fft2(image)
    fshift = np.fft.fftshift(f)
    def make_transform_matrix(d):
        transfor_matrix = np.zeros(image.shape)
        center_point = tuple(map(lambda x:(x-1)/2,s1.shape))
        for i in range(transfor_matrix.shape[0]):
            for j in range(transfor_matrix.shape[1]):
                def cal_distance(pa,pb):
                    from math import sqrt
                    dis = sqrt((pa[0]-pb[0])**2+(pa[1]-pb[1])**2)
                    return dis
                dis = cal_distance(center_point,(i,j))
                transfor_matrix[i,j] = np.exp(-(dis**2)/(2*(d**2)))
        return transfor_matrix
    d_matrix = make_transform_matrix(d)
    new_img = np.abs(np.fft.ifft2(np.fft.ifftshift(fshift*d_matrix)))
    return new_img
def cal_distance(pa, pb):
    dis = math.sqrt((pa[0] - pb[0]) ** 2 + (pa[1] - pb[1]) ** 2)
    return dis
def HighPassFilter(image, d, n, s1):
    f = np.fft.fft2(image)
    fshift = np.fft.fftshift(f)
    def make_transform_matrix(d):
        transform_matrix = np.zeros(image.shape)
        center_point = tuple(map(lambda x: (x - 1) / 2, s1.shape))
        for i in range(transform_matrix.shape[0]):
            for j in range(transform_matrix.shape[1]):
                dis = cal_distance(center_point, (i, j))
                transform_matrix[i, j] = 1 / (1 + (d / dis) ** (2 * n))
        return transform_matrix
    d_matrix = make_transform_matrix(d)
    image_filtered = np.abs(np.fft.ifft2(np.fft.ifftshift(fshift * d_matrix)))
    return image_filtered
def GossFredomain(image):
    img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    f = np.fft.fft2(img)
    fshift = np.fft.fftshift(f)
    s1 = np.log(np.abs(fshift))
    img_l1 = GaussianLowFilter(img, 5,s1)
    img_l2 = GaussianLowFilter(img, 10,s1)
    img_l3 = GaussianLowFilter(img, 20,s1)
    img_h1 = HighPassFilter(img, 2,1,s1)
    img_h2 = HighPassFilter(img, 2,0.8,s1)
    img_h3 = HighPassFilter(img, 2,0.6,s1)
    # Display each image in a subplot
    fig, axs = plt.subplots(2, 3)
    axs[0, 0].imshow(img_l1,cmap="gray")
    axs[0, 0].set_title("GD D=5")
    axs[0, 1].imshow(img_l2,cmap="gray")
    axs[0, 1].set_title("GD D=10")
    axs[0, 2].imshow(img_l3,cmap="gray")
    axs[0, 2].set_title("GD D=20")
    axs[1, 0].imshow(img_h1,cmap="gray")
    axs[1, 0].set_title("GH N=1")
    axs[1, 1].imshow(img_h2,cmap="gray")
    axs[1, 1].set_title("GH N=0.8")
    axs[1, 2].imshow(img_h3,cmap="gray")
    axs[1, 2].set_title("GH N=0.6")
    plt.subplots_adjust(wspace=0.5, hspace=0.5)
    zipper = "result_folder"
    result_file_path = os.path.join(zipper, "Goss.jpg")
    plt.savefig(result_file_path)

一二阶算子实现

算法函数分析

在这里插入图片描述
设上图最上面部分的灰度剖面图对应于图像中的一条具有代表性的水平像素线,其中包括了

  1. 灰度较缓变化的斜坡(软边缘)
  2. 孤立点(很可能为噪声)
  3. 细线(细节)
  4. 以及灰度跳变的阶梯(硬边缘)

为了简单起见,考虑图像中只有8个灰度级的情况。图中下面的一行给出了这条像素线中各个像素的灰度值,由此计算出的一阶微分和二阶微分在图中的第3行和第4行中给出。由于这里的像素线在图像中是水平分布的,因此微分方程也是一维的,一维情况下的一阶微分:
在这里插入图片描述
二阶微分:
在这里插入图片描述

效果分析

  • 首先注意到沿着整个斜坡(软边缘),一阶微分都具有非0响应,并且当这种斜坡的灰度过渡近似线时,对应于变化率的一阶微分的响应为恒定值(这里为-1);而二阶微分的非0响应则只出现在斜坡的起始和终点处,在灰度变化率恒定的斜面上二阶微分值为0,这就是拉普拉斯锐化图像周围出现双边缘的原因。由此得出结论,对于图像中的软边缘,一阶微分通常产生较粗的边缘,而二阶微分则细得多。

  • 再来看孤立噪声点,注意到二阶微分对于噪声点的响应较一阶微分要强很多,这也就是拉普拉斯锐化图像中出现一些零星的高响应的原因。
    细线常常对应于图像中的细节,二阶微分对细线的较强响应说明了二阶微分对于细节增强的优越性。

  • 同时可以得到的结论是一、二阶微分对于灰度阶梯有着相同的响应,只是在二阶微分中有一个从正到负的过渡,这一性质用于边缘检测。
    所以,我们可以将其对应阶级算子的优势进行针对性的使用

  • 边缘检测:一阶和二阶算子可以帮助我们检测图像中的边缘。一阶算子通常可以提供边缘的位置和方向信息,而二阶算子可以提供更精确的边缘位置。

  • 边缘增强:一阶和二阶算子可以增强图像中的边缘,使其更加明显和清晰。通过突出边缘的变化和细节,图像看起来更加锐利。

  • 噪声增强:一阶和二阶算子对噪声比较敏感,因为它们可以放大边缘和细节。如果图像中存在较多的噪声,算子运行后可能会使噪声更加明显。

  • 细节增强:一阶和二阶算子可以帮助我们提取和增强图像中的细节。通过突出图像的纹理、纹理边缘和细微变化,图像看起来更加丰富和详细。

需要注意的是,一阶和二阶算子的运行结果可能会因图像的特性、算子的选择和参数设置而有所不同。因此,在应用这些算子时,需要进行实验和调整参数,以达到最佳的图像锐化效果。此外,锐化操作可能会引入一些不必要的噪声和伪影,因此在实际应用中需要谨慎使用,并结合其他图像处理技术进行综合处理。

算法原理

Convolution函数是为了实现图像卷积,接受卷积核并适当地修改图像。

  • Roberts函数是属于一阶算子的应用
  • Sobel函数同样是一阶算子应用
  • Laplacian函数为二阶算子应用
  • Algorithm函数是将三种执行微分算子进行综合

并将四幅图像前后对比展示下载到本地,供图像处理系统调用操作和现实

图像卷积核预处理
在这里插入图片描述

创建一个新的图像作为卷积结果的存储空间。复制输入的图像大小与对应矩阵。
使用嵌套的循环遍历输入图像的像素,跳过第一列和最后一列(因为卷积核的大小为3x3,边缘像素无法完全卷积)且卷积核设定
对于每个像素,计算其周围3x3区域内的卷积操作。使用tmp变量初始化为0,用于累加卷积结果。也就是为了后期数组的像素操作
内部的两个循环遍历卷积核的每个元素,并将周围像素与卷积核的对应元素相乘,然后将乘积累加到tmp[][]中。
将累加结果取绝对值,并将其赋值给新图像的对应像素位置并返回。

Roberts函数实现

一阶微分是通过梯度法来实现的。对于图像f(i,j),它在点(i,j)处的梯度是一个矢量,定义为:
在这里插入图片描述
利用差分法近似上述公式,得到:
在这里插入图片描述

利用差分运算时,图像的第一行和第一列的像素的梯度无法求得,一般用后一行或后一列的梯度值近似代替。微分运算可以增强图像高频分量(边缘等细节),但是仅仅微分处理后的图像非常暗,因此既要增强图像边缘,又要保持目标物体的内部灰度不变,常采用给边缘规定一个特定的灰度级的方法来完成梯度锐化处理。公式为:
在这里插入图片描述

La为一指定的灰度值,它将边界的灰度值统一化,这样可以使其边界更加清晰明显。该方法基本上不破坏图像的背景,又可找到边缘,并根据需要增强边缘。代码中的 Roberts 算子是一种经典的边缘检测算法,它通过计算像素点与其相邻像素之间的差值来确定边缘的位置。边缘通常表示图像中灰度变化剧烈的区域,而 Roberts 算子能够对水平和垂直方向的边缘进行检测,从而提取出图像中的细节和轮廓信息。
通过应用 Roberts 算子,这段代码可以将输入的图像进行边缘检测,并将检测到的边缘信息保存在输出的图像中。这对于数字图像识别任务非常有意义,因为提取图像边缘有助于识别物体的形状、边界和轮廓,进而实现物体的分类、定位和识别。
根据任一对互相垂直方向上的差分可用来计算梯度的原理,采用对角线方向相邻像素之差进行梯度幅度检测,其检测水平、垂直方向边缘的性能要好于斜线方向边缘,并且检测定位精度比较高,但对噪声敏感。
在这里插入图片描述

Sobel函数

从纵向和横向两个方向Sobel 算子是一种用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导。该算子用于计算图像明暗程度近似值,根据图像边缘旁边明暗程度把该区域内超过某个数的特定点记为边缘。对灰度图像进行水平和垂直方向的差分计算
Sobel 算子的水平和垂直差分算子对应着两个卷积核,将水平和垂直差分的结果进行加权求和,可以得到每个像素点的边缘强度。
阈值处理:根据阈值将边缘强度映射为二值图像,即将边缘像素设置为白色(255),非边缘像素设置为黑色(0),以便于边缘的提取和分割。
在这里插入图片描述

G = (c-g)/4 * [ 1, 1]+(a-i)/4 * [-1, 1]+(b-h)/2 * [ 0, 1]+(f-d)/2 * [ 1, 0]
以c点为例,c–>a为x的正方向,再a–>g,为y的正方向,因此,c–>g的方向就是[ 1, 1],代表c–>g是先走c–>b–>a,再走a–>d–>g,所以两个方向都是正的,即[ 1, 1]。其他的都一样。x方向和y方向分别相加后,得到:G = [(c-g-a+i)/4 + (f-d)/2, (c-g+a-i)/4 + (b-h)/2]乘以4以后,将得到下面两个方向算子

Laplacian函数

拉普拉斯(Laplacian)算子是 n 维欧几里德空间中的一个二阶微分算子,常用于图像增强领域和边缘提取。它通过灰度差分计算邻域内的像素,基本流程是:
判断图像中心像素灰度值与它周围其他像素的灰度值;
如果中心像素的灰度更高,则提升中心像素的灰度;
反之降低中心像素的灰度,从而实现图像锐化操作。
在算法实现过程中,Laplacian 算子通过对邻域中心像素的四方向或八方向求梯度,再将梯度相加起来判断中心像素灰度与邻域内其他像素灰度的关系,最后通过梯度运算的结果对像素灰度进行调整,代码块选择了四邻域的实现

代码组实现

def convolution(img_old, kernel):
    img_new = np.zeros(img_old.shape, dtype=int)
    for i in range(1, img_new.shape[0] - 1):  # 第一列和最后一列不用处理
        for j in range(1, img_new.shape[1] - 1):
            tmp = 0  # 初始化为0,用来求和
            for k in range(-1, 2):
                for l in range(-1, 2):
                    tmp += img_old[i + k][j + l] * kernel[k + 1][l + 1]
            img_new[i][j] = abs(tmp)
    return img_new
def roberts(image):
    img_roberts=np.zeros(image.shape,dtype=int)
    for i in range(1,image.shape[1]-1):
        for j in range(1,image.shape[1]-1):
            img_roberts[i][j]=abs((int)(image[i+1][j+1]-(int)(image[i][j]))
                                  +abs((int)(image[i + 1][j]) - (int)(image[i][j + 1])))
    return img_roberts
def sobel(image):
    kernel_horizontal = np.array([[1, 2, 1],
                                  [0, 0, 0],
                                  [-1, -2, -1]])
    image_horizontal = convolution(image, kernel_horizontal)
    kernel_vertical = np.array([[1, 0, -1],
                                [2, 0, -2],
                                [1, 0, -1]])
    image_vertical = convolution(image, kernel_vertical)
    image_sobel=img_Sobel = np.sqrt(image_vertical*image_vertical + image_horizontal*image_horizontal)
    image_sobel=np.minimum(image_sobel,255)
    return image_sobel
def Laplacian(image):
    kernel_Laplacian1 = np.array([[0, -1, 0],
                                  [-1, 4, -1],
                                  [0, -1, 0]])
    img_Laplacian1 = convolution(image, kernel_Laplacian1)
    img_Laplacian1 = abs(img_Laplacian1)
    return img_Laplacian1
def algroithm(image):
   image=image[:,:,0]
   fig, axs = plt.subplots(2, 2)
   axs[0, 0].imshow(image, cmap="gray")
   axs[0, 0].set_title("Original")
   image_roberts=roberts(image)
   axs[0,1].set_title("Roberts")
   axs[0,1].imshow(image_roberts, cmap="gray")
   image_sobel=sobel(image)
   axs[1,0].set_title("Sobel")
   axs[1,0].imshow(image_sobel, cmap="gray")
   img_Laplacian1=Laplacian(image)
   axs[1,1].set_title("Laplacian")
   axs[1,1].imshow(img_Laplacian1, cmap="gray")
   plt.subplots_adjust(wspace=0.5, hspace=0.5)
   zipper = "result_folder"
   result_file_path = os.path.join(zipper, "alogrithm.jpg")
   plt.savefig(result_file_path)
def intergation(image):
   rgb_to_hsv(image)
   convert_to_gray(image)
   PFTdomain(image)
   GossFredomain(image)
   algroithm(image)

程序可视化

搭建一个完整的可视化运行界面

def browse_image():
    global selected_image_path
    filename = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
    if filename:
        # 清空之前的图片
        if image_label.winfo_exists():
            image_label.pack_forget()
        image = Image.open(filename)
        image = image.resize((500, 500))  # 调整图片大小
        photo = ImageTk.PhotoImage(image)
        image_label.config(image=photo)
        image_label.image = photo
        image_label.pack()
        selected_image_path=filename
def convert_to_unicode_escape(path):
    # 将非ASCII字符转换为Unicode转义序列
    path = path.encode('unicode_escape').decode()
    return path
def polishpicture(num,image_path):
     img = cv.imread(image_path, 1)
     if img is None:
         messagebox.showinfo("无法加载图像")
     num=float(num)
     new_img =GammaTranform(1,num,img)
     cv.imshow('polishpicture',new_img)
     cv.imwrite('demon.jpg',new_img)
     cv.waitKey(0)
def process_image_path(data):
    num=entry.get()
    if num.lower() == "end":
        messagebox.showinfo("测试结束", "测试已结束!")
        window.destroy()
    else:
        try:
            num = float(num)  # 尝试将内容转换为浮点数
            polishpicture(num,selected_image_path)
        except ValueError:
            messagebox.showinfo("测试数据错误","请重新输入合理数据")
            entry.delete(0, tk.END)
def Intergre(image_path):
    path=convert_to_unicode_escape(image_path)
    image=cv.imread(path)
    intergation(image)
def process_image_path():
    file_path = filedialog.askopenfilename()
    # 调用 Intergration() 函数并传递图像路径作为参数
    Intergre(file_path)
result_folder = "result_folder"
if not os.path.exists(result_folder):
    os.makedirs(result_folder)
# 获取处理结果文件夹中的所有图像文件
result_files = [f for f in os.listdir(result_folder) if os.path.isfile(os.path.join(result_folder, f))]
def show_image(file_path):
    image = Image.open(file_path)
    image.show()
def show_processed_images():
    # 创建一个新窗口来展示处理结果
    result_window = tk.Toplevel(window)
    result_window.title("处理结果")

    # 在新窗口中展示处理后的图像
    for file_name in result_files:
        file_path = os.path.join(result_folder, file_name)
        image_button = tk.Button(result_window, text=file_name, command=lambda
            path=file_path: show_image(path))
        image_button.pack()
def center_window(window):
    window.update_idletasks()
    width = window.winfo_width()
    height = window.winfo_height()
    x = (window.winfo_screenwidth() // 2) - (width // 2)
    y = (window.winfo_screenheight() // 2) - (height // 2)
    window.geometry('{}x{}+{}+{}'.format(width, height, x, y))

window = tk.Tk()
window.title("图像集成处理器")
window.geometry("800x700+500+500")
center_window(window)
entry = tk.Entry(window)
entry.pack()
button1 = tk.Button(window, text="输入调节的数据", command=lambda: process_image_path(entry.get()))
button1.pack()
sendbutton=tk.Button(window,text="图像浏览",command=browse_image)
sendbutton.pack()
button2 = tk.Button(window, text="集成处理图像对比", command=process_image_path)
button2.pack()
show_results_button = tk.Button(window, text="展示处理结果", command=show_processed_images)
show_results_button.pack()
image_label=tk.Label(window)
# 运行窗口的主循环
window.mainloop()


运行结果

在这里插入图片描述
可以在新生成的图像界面之后点击需要展示的图像
请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

结语

计算机数字图像处理入门操作的集成讲解,代码和原理都做了充足的介绍,如果需要全部的源码可以直接下载,这也是最近两个月选修课的一些任务结果咯。

  • 此去经年应由事
  • 不见当年凤凰台

that is all

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

磊哥哥讲算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值