數字圖像處理-空間域處理-灰度變換-基本灰度變換函數(反轉變換、對數變換、伽馬變換和分段線性變換)


總結性的一篇博文,內容其實很簡單,之所以寫出來是為了對自己之前所學做一些總結。

參考自:《數字圖像處理》--第三版--岡薩勒斯--中,以及師兄提供的參考資料,在此對師兄表示感謝。

 

空間域處理是直接對像素進行操作的方法,這是相對於頻率域處理而言的。空間域處理主要分為兩大類:灰度變換和空間濾波。灰度變換在圖像單個像素上操作,主要以對比度和閾值處理為目的。空間濾波涉及改善性能的操作,通過像元領域來處理。

空間域處理均可由下式表達:

 

表示f(x, y)輸入圖像,g(x,y) 表示輸出圖像,T 是變換算子(數學規則)

灰度變換可以看作領域大小為1*1的空間域處理,這這種情況下上式變為灰度變換函數:

rs分別為輸入、輸出灰度

基本的灰度變換函數

常用的基本函數有三類:線性函數,對數函數(對數和反對數)和冪律函數(n次冪和n次根)

圖像反轉

適用於增強嵌入在一幅圖像暗區域中的白色或灰色細節。變換公式為:

圖像灰度級范圍為[0,L-1]

"""反轉變換"""
import numpy as np
import cv2
import matplotlib.pyplot as plt


def reverse(img):
    output = 255 - img
    return output


img1 = cv2.imread(r'F:\program_study\Python\data\breast.tif')  # 前頭加r是消除反斜杠轉義
cv2.imshow('input', img1)
x = np.arange(0, 256, 0.01)
y = 255 - x
plt.plot(x, y, 'r', linewidth=1)
plt.title('反轉變換函數圖')
plt.xlim([0, 255]), plt.ylim([0, 255])
plt.show()
img_output = reverse(img1)
cv2.namedWindow('output', cv2.WINDOW_NORMAL)  # 可改變窗口大小
cv2.imshow('output', img_output)
cv2.waitKey(0)
cv2.destroyAllWindows()
反轉變換

對數變換

對數變換可以拉伸范圍較窄的低灰度值,同時壓縮范圍較寬的高灰度值。可以用來擴展圖像中的暗像素值,同時壓縮亮像素值。

其中c為常數,r加1可以使函數向左移一個單位,得到的s均大於0。

一個典型的應用是傅立葉頻譜(幅度譜)的顯示。對傅立葉頻譜進行對數變化,左圖中藍線為變換函數,注意x軸量級為10的7次方,直接被壓縮到了0-17.5,效果非常明顯。右圖是經過對數變換,又經過最大最小值變換后的頻譜。

 

一般對數變換

"""對數變換"""
import numpy as np
import matplotlib.pyplot as plt
import cv2


def log_plot(c):
    x = np.arange(0, 256, 0.01)
    y = c*np.log(1 + x)
    plt.plot(x, y, 'r', linewidth=1)
    plt.title('對數變換函數')
    plt.xlim(0, 255), plt.ylim(0, 255)
    plt.show()


def log(c, img):
    output_img = c*np.log(1.0+img)
    output_img = np.uint8(output_img+0.5)
    return output_img


img_input = cv2.imread('F:\program_study\Python\data\pollens.tif')
cv2.imshow('input', img_input)
log_plot(42)
img_output = log(42, img_input)
cv2.imshow('output', img_output)
cv2.waitKey(0)
cv2.destroyAllWindows()
對數變換

冪律(伽馬)變換

變換的基本形式為:

 

c和γ為正常數

對於不同的γ值,有不同的曲線

 

多用在圖像整體偏暗,擴展灰度級。另外一種情況是,圖像有“沖淡”的外觀(很亮白)需要壓縮中高以下的大部分的灰度級。

"""冪律變換(伽馬)"""
import numpy as np
import matplotlib.pyplot as plt
import cv2


def gamma_plot(c, v):
    x = np.arange(0, 256, 0.01)
    y = c*x**v
    plt.plot(x, y, 'r', linewidth=1)
    plt.title('伽馬變換函數')
    plt.xlim([0, 255]), plt.ylim([0, 255])
    plt.show()


def gamma(img, c, v):
    lut = np.zeros(256, dtype=np.float32)
    for i in range(256):
        lut[i] = c * i ** v
    output_img = cv2.LUT(img, lut)
    output_img = np.uint8(output_img+0.5)  # 這句一定要加上
    return output_img


img_input = cv2.imread('F:\program_study\Python\data\city.tif', cv2.IMREAD_GRAYSCALE)
cv2.imshow('imput', img_input)
gamma_plot(0.00000005, 4.0)
img_output = gamma(img_input, 0.00000005, 4.0)
cv2.imshow('output', img_output)
cv2.waitKey(0)
cv2.destroyAllWindows()
伽馬變換

分段線性變換

  對比度拉伸

"""分段線性變換Segmental Linear Transformation"""
import cv2
import numpy as np
import matplotlib.pyplot as plt


def SLT(img, x1, x2, y1, y2):
    lut = np.zeros(256)
    for i in range(256):
            if i < x1:
                lut[i] = (y1/x1)*i
            elif i < x2:
                lut[i] = ((y2-y1)/(x2-x1))*(i-x1)+y1
            else:
                lut[i] = ((y2-255.0)/(x2-255.0))*(i-255.0)+255.0
    img_output = cv2.LUT(img, lut)
    img_output = np.uint8(img_output+0.5)
    return img_output


def SLT_plot(x1, x2, y1, y2):
    plt.plot([0, x1, x2, 255], [0, y1, y2, 255], 'b', linewidth=1)
    plt.plot([x1, x1, 0], [0, y1, y1], 'r--')
    plt.plot([x2, x2, 0], [0, y2, y2], 'r--')
    plt.title('分段線性變換函數')
    plt.xlim([0, 255]), plt.ylim([0, 255])
    plt.show()


input_img = cv2.imread('F:\program_study\Python\data\Einstein.tif', cv2.IMREAD_GRAYSCALE)
cv2.imshow('input', input_img)
img_x1 = 100
img_x2 = 160
img_y1 = 30
img_y2 = 230
SLT_plot(img_x1, img_x2, img_y1, img_y2)
output_img = SLT(input_img, img_x1, img_x2, img_y1, img_y2)
cv2.imshow('output', output_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
對比度拉伸

  灰度級分層

"""灰度級分層"""
import numpy as np
import cv2


def GrayLayer(img):
    lut = np.zeros(256, dtype=np.uint8)
    layer1 = 30
    layer2 = 60
    value1 = 10
    value2 = 250
    for i in range(256):
        if i >= layer2:
            lut[i] = value1
        elif i >= layer1:
            lut[i] = value2
        else:
            lut[i] = value1
    ans = cv2.LUT(img, lut)
    return ans


img_input = cv2.imread('F:\program_study\Python\data\LandsatImage.tif', cv2.IMREAD_GRAYSCALE)
cv2.imshow('input', img_input)
img_output = GrayLayer(img_input)
cv2.imshow('output', img_output)
# cv2.imwrite('LandsatImage_grayLayer.tif', img_output)
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度級分層

  二值化

"""閾值化,其實就是二值化"""
import cv2

img_input = cv2.imread('F:\program_study\Python\data\Lena.tif', cv2.IMREAD_GRAYSCALE)
cv2.imshow('input', img_input)
threshold = 110
img_input[img_input > threshold] = 255  # 二值化
img_input[img_input <= threshold] = 0  # 二值化
cv2.imshow('output', img_input)
# cv2.imwrite('Lena_thresholding.tif', f)
cv2.waitKey(0)
cv2.destroyAllWindows()
二值化

  最大最小值拉伸

 

"""最大最小值拉伸"""
import numpy as np
import matplotlib.pyplot as plt
import cv2


def max_min_strech(img):
    max1 = np.max(img)
    min1 = np.min(img)
    output_img = (255.0*(img-min1))/(max1-min1)  # 注意255.0 而不是255 二者算出的結果區別很大
    output_img1 = np.uint8(output_img+0.5)
    return output_img1


img_input = cv2.imread('F:\program_study\Python\data\Einstein.tif', cv2.IMREAD_GRAYSCALE)
cv2.imshow('input', img_input)
x = (np.min(img_input), np.max(img_input))
y = (0, 255)
plt.plot(x, y, 'b', linewidth=1)
plt.title('最大最小拉伸函數')
plt.xlim(0, 255)
plt.show()
img_output = max_min_strech(img_input)
cv2.imshow('output', img_output)
cv2.waitKey(0)
cv2.destroyAllWindows()


# 最大最小值拉伸的實質是找線性函數,兩點求直線方程,x1是拉伸前的最小值,
# y1是拉伸后的最小值;x2是拉伸前的最大值,y2是拉伸后的最大值
最大最小值拉伸

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM