【问题标题】:Laplacian sharpening - grey image as result拉普拉斯锐化 - 结果为灰色图像
【发布时间】:2017-01-29 20:40:40
【问题描述】:

与我之前的许多人一样,我正在尝试实现 Gonzalez 和 Woods “数字图像处理”一书中的图像锐化示例。

我创建一个负拉普拉斯核 (-1, -1, -1; -1, 8, -1; -1, -1,-1) 并将其与图像进行卷积,然后从原始结果中减去结果图片。 (我还尝试采用正拉普拉斯算子 (1, 1, 1; 1, -8, 1; 1, 1, 1) 并将其添加到图像中)。在每个阶段,我都会将结果拟合到 (0, 255) 范围内,归一化的拉普拉斯算子看起来不错,而且像预期的那样是灰色的。

import matplotlib.cm as cm
import scipy.misc
import scipy.ndimage.filters

#Function for plotting abs:
pic_n = 1
def show_abs(I, plot_title):
    plt.title(plot_title)
    plt.tight_layout()
    plt.axis('off')
    plt.imshow(abs(I), cm.gray)

#Reading the image into numpy array:
A = scipy.misc.imread('moon1.jpg', flatten=True)

plt.figure(pic_n)
pic_n += 1
show_abs(A, 'Original image')

A          -= np.amin(A) #map values to the (0, 255) range
A          *= 255.0/np.amax(A)

#Kernel for negative Laplacian
kernel      = np.ones((3,3))*(-1)
kernel[1,1] = 8

#Convolution of the image with the kernel:
Lap         = scipy.ndimage.filters.convolve(A, kernel)

#Laplacian now has negative values in range (-255, 255):
print('L', np.amax(Lap), np.amin(Lap))

plt.figure(pic_n)
pic_n += 1
show_abs(Lap, 'Laplacian')

#Map Laplacian to the (0, 255) range:
Lap        -= np.amin(Lap)
Lap        *= 255.0/np.amax(Lap)
print('L', np.amax(Lap), np.amin(Lap))

plt.figure(pic_n)
pic_n += 1
show_abs(Lap, 'Normalized Laplacian')

A         += Lap #Add negative Laplacian to the original image

print('A', np.amax(A), np.amin(A))
A          -= np.amin(A)
A          *= 255.0/np.amax(A)
print('A', np.amax(A), np.amin(A))

plt.figure(pic_n)
pic_n += 1
show_abs(A, 'Laplacian filtered img')

plt.show()

原图:

结果:

问题是最终锐化的图像看起来褪色和灰色。我尝试进行直方图均衡以使其更具对比度,但结果很奇怪。我考虑过应用 gamma 校正,但我不喜欢自愿选择 gamma 系数。

似乎必须有一种简单方便的方法将图像恢复到原始动态范围。我将不胜感激有关代码的想法和 cmets。谢谢!

【问题讨论】:

    标签: python image-processing scipy


    【解决方案1】:

    在我看来,部分问题与您如何重新调整Lap 有关。我认为您不想先减去最小值-锐化应该会降低某些像素的强度并增加其他像素的强度。您可能还希望使用乘以 Lap 的缩放因子来控制锐化程度(255 可能太极端了)。

    背景在最终图像中看起来是灰色的原因可能是因为在添加了负拉普拉斯算子后,月球中的像素会比背景暗(这部分图像中拉普拉斯算子的大小会更大,因为它包含更多的局部结构)。这意味着您重新缩放背景像素将映射到某个值 > 0。如果您不从Lap 中减去最小值,那么这些较暗的像素将具有负值,因此您可以在结果中剪切像素值图像,使它们都 > 0。这样你最终会得到一个纯黑色的背景。

    【讨论】:

    • 您好,感谢您的回答!你的意思是我应该首先在图像中添加具有负值的拉普拉斯算子,然后再进行缩放?或者我应该将拉普拉斯算子重新缩放到 0 到 255 之间的某个区间 - 如果是,如何选择它以确保背景变黑?
    • 我会缩放拉普拉斯算子(仍然包含负值),将其添加到图像中,然后可能截断结果数组,使所有像素值都大于零。
    • 谢谢,这帮了我很大的忙,但我仍然无法理解它是如何工作的 :( 我明白了你关于使用拉普拉斯比例因子的想法。背景现在保持纯黑色,但是锐化因子越高 - 图像越暗。我所拥有的:1) 将原始图像缩放到 (255.0, 0.0) 2) 取 (-1, -1, -1; -1, 8, -1; -1, -1,-1) 内核并将其与图像进行卷积。结果“Lap”的值在 (1151.0, -1166.0) 范围内。
    • 3) 将 Lap 乘以 'factor/np.amax(Lap)' 根据所需的锐化因子缩放 Lap,因为因子 = 100 Lap 位于 (100.0, -101.303) 范围内。 4) 将图像和圈数相加。我希望生成的锐化图像位于 (355.0, -101.303) 范围内,但是它恰好在 (350.917, -81.06) 范围内 - 为什么??
    • 5) 取结果的绝对值会给出带有黑色背景的锐化图像,因为正如您所说,背景应该具有最小值,'abs' 将锐化图像缩放为 (350.917 , 0.0) 范围。生成的图像看起来很锐利,但很暗 - 可能仍然没有正确缩放。
    【解决方案2】:

    按照 ali_m 的建议更正代码后,我应用了局部直方图均衡化 - 它会减慢代码速度并增加对 OpenCV 库的依赖,但生成的图像看起来不错。

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import scipy.misc
    import scipy.ndimage.filters
    import cv2
    
    #Function for plotting abs:
    pic_n       = 1
    def show_abs(I, plot_title):
        plt.title(plot_title)
        plt.tight_layout()
        plt.axis('off')
        plt.imshow(abs(I), cm.gray)
    
    #Reading of the image into numpy array:
    A0           = scipy.misc.imread('moon1.jpg', flatten=True)
    A0          -= np.amin(A0)#map values to the (0, 255) range
    A0          *= 255.0/np.amax(A0)
    print('Img         ', np.amax(A0), np.amin(A0))
    #>>> Img          255.0 0.0
    
    #Kernel for negative Laplacian
    kernel      = np.ones((3,3))*(-1)
    kernel[1,1] = 8
    
    #Convolution of the image with the kernel:
    Lap        = scipy.ndimage.filters.convolve(A0, kernel)
    
    #Laplacian now has negative values
    print('Original Lap', np.amax(Lap), np.amin(Lap))
    #>>> Original Lap 1151.0 -1166.0
    
    #Map Laplacian to some new range:
    Laps        = Lap*100.0/np.amax(Lap) #Sharpening factor!
    print('Scaled Lap  ', np.amax(Laps), np.amin(Laps))
    #>>> Scaled Lap   100.0 -101.303
    
    plt.figure(pic_n)
    pic_n += 1
    plt.subplot(1,2,1)
    show_abs(Lap, 'Laplacian')
    plt.subplot(1,2,2)
    show_abs(Laps, 'Scaled Laplacian')
    
    A           = A0 + Laps #Add negative Laplacian to the original image
    
    print('SharpImg    ', np.amax(A), np.amin(A))
    #>>> SharpImg     350.917 -81.06
    
    A = abs(A) #Get rid of negative values
    print('SharpImg abs', np.amax(A), np.amin(A))
    
    A           *= 255.0/np.amax(A)
    print('SharpImg after scaling', np.amax(A), np.amin(A))
    #>>> SharpImg abs 350.917 0.0
    
    # Local Histogram Equalization with OpenCV:
    A_cv2       = A
    A_cv2       = A_cv2.astype(np.uint8)
    
    tile_s0     = 4
    tile_s1     = 4
    
    clahe       = cv2.createCLAHE(clipLimit=1, tileGridSize=(tile_s0,tile_s1))
    A_cv2       = clahe.apply(A_cv2)
    
    plt.figure(pic_n)
    pic_n += 1
    plt.subplot(2,1,1)
    plt.hist(A_cv2)
    plt.title('Original Histogram')
    plt.subplot(2,1,2)
    plt.hist(A_cv2)
    plt.title('Locally Equalized Histogram')
    
    plt.figure(pic_n)
    pic_n += 1
    plt.subplot(1,3,1)
    show_abs(A0, 'Original image')
    plt.subplot(1,3,2)
    show_abs(A, 'Laplacian filtered img')
    plt.subplot(1,3,3)
    show_abs(A_cv2, 'Local Hist equalized img')
    plt.show()
    

    【讨论】:

      【解决方案3】:

      我最近也为此苦苦挣扎,直到我意识到 Gonzalez & Woods 中的示例是使用 Matlab 完成的,其中 imshow 函数似乎截断了双精度值(所有低于 0 的值都设置为 0 -以上所有值都设置为 1)。

      所以做这样的事情对我有用:

        imgfloat = L.astype(np.float32) / 255
        imgLaplacian = cv2.filter2D(imgfloat, cv2.CV_32F, self.sharpeningKernel)
        res = imgfloat - imgLaplacian
        res[res < 0.0] = 0.0
        res[res > 1.0] = 1.0
      
        res = (res * 255).astype(np.uint8)
      

      将sharpeningKernel定义为

        self.sharpeningKernel = np.zeros((3,3),np.float32)
        self.sharpeningKernel[0,1] = 1.0
        self.sharpeningKernel[1,0] = 1.0
        self.sharpeningKernel[1,1] = -4.0
        self.sharpeningKernel[1,2] = 1.0
        self.sharpeningKernel[2,1] = 1.0
      

      【讨论】:

        【解决方案4】:

        两年后回到同样的任务,我将代码细化如下:

        import numpy as np
        import matplotlib.pyplot as plt
        import scipy.misc
        import scipy.ndimage.filters
        
        # Function for plotting abs:
        pic_num       = 1
        def show_abs(I, plot_title, pic_num):
            plt.figure(pic_num)
            plt.title(plot_title)
            plt.tight_layout()
            plt.axis('off')
            plt.imshow(abs(I), plt.cm.gray)
            return pic_num+1
        
        # Reading of the image into numpy array:
        A0           = scipy.misc.imread('moon1.jpg', flatten=True)
        # Map values to the (0, 255) range:
        A0           = (A0 - np.amin(A0))*255.0 /(np.amax(A0)-np.amin(A0)) 
        
        # Kernel for negative Laplacian:
        kernel      = np.ones((3,3))*(-1)
        kernel[1,1] = 8
        
        # Convolution of the image with the kernel:
        Lap        = scipy.ndimage.filters.convolve(A0, kernel)
        
        #Map Laplacian to some new range:
        ShF         = 100                   #Sharpening factor!
        Laps        = Lap*ShF/np.amax(Lap) 
        
        # Add negative Laplacian to the original image:
        A           = A0 + Laps 
        # Set negative values to 0, values over 255 to 255:
        A = np.clip(A, 0, 255)
        
        # Image the result:
        pic_num = show_abs(Laps, 'Scaled Laplacian', pic_num)
        pic_num = show_abs(A, 'Sharpened image', pic_num)
        plt.show()
        

        所以上面代码的两个 cmets 都是正确的:我不应该重新调整拉普拉斯算子,并且通过 numpy-clipping 将锐化的图像拟合到 (0, 255) 中会得到一个很好的结果。到目前为止,不需要 OpenCV 和直方图均衡化。

        【讨论】:

          猜你喜欢
          • 2012-12-03
          • 2016-08-09
          • 2021-09-09
          • 1970-01-01
          • 2019-04-13
          • 2018-11-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多