文章目录

  • 21. 直方图归一化 (Histogram Normalization)
  • 22. 直方图操作(直方图平坦化)
  • 23. 直方图均衡化(Histogram Equalization)
  • 24. 伽马校正(Gamma Correction)
  • 25. 最近邻插值 (Nearest-neighbor Interpolation)


21. 直方图归一化 (Histogram Normalization)

直方图会存在偏差.比如说,数据集中在0处(左侧)的图像会整体偏暗,数据集中在255处(右侧)的图像会偏亮.如果直方图有所偏向,那么其动态范围(dynamic range)就会较低.为什么使得人能够更好清除地看见图片,让直方图归一化,平坦化是十分必要的.

这种归一化直方图的操作被称为灰度变换(Grayscale Transformation). 像素点取值范围从[c,d]转换到[a,b]的过程由下面的式子定义.

outVal = {
	a                                 if(inVal <c)
	(b-a) / (d-c) * (inVal - c) + a   if(c <= inVal <=d)
	b                                 if(inVal > d)
}

实现代码:

# @Time   : 2022/6/11 10:15
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
import matplotlib.pyplot as plt

# histogram normalization
def hist_normalization(image, a=0, b=255):
    # get max and min
    c = image.min()
    d = image.max()
    out = image.copy()

    # normalization
    out = (b - a) / (d - c) * (out - c) + a
    out[out < a] = a
    out[out > b] = b
    out = out.astype(np.uint8)
    return out


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)
    H,W = imageOriginal.shape[:2]
    out = hist_normalization(imageOriginal)

    # Dist histogram
    ax1 = plt.subplot(1,2,1)
    plt.hist(imageOriginal.ravel(),bins=255,rwidth=0.8,range=(0,255))
    # plt.hist(imageOriginal.ravel(),bins=255,rwidth=0.8,range=(0,255))
    ax2 = plt.subplot(1,2,2)
    plt.hist(out.ravel(),bins=255,rwidth=0.8,range=(0,255))
    plt.show()

22. 直方图操作(直方图平坦化)

这里的直方图操作不是变更直方图的动态范围,而是让直方图变得更加的平坦.

可以使用下面的公式将平均值为m标准差为s的直方图变成平均值为m0标准差为s0的直方图:

opencv 怎么分离出水印 opencvfindhomography_opencv 怎么分离出水印


让直方图的平均值m0 = 128, 标准差 s0 = 52.

代码实现:

# @Time   : 2022/6/11 11:19
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
import matplotlib.pyplot as plt


# histogram manipulation
def hist_operate(image, m0=128, s0=52):
    m = np.mean(image)
    s = np.std(image)

    out = image.copy()

    # normalize
    out = s0 / s * (out - m) + m0
    out = np.clip(out, 0, 255)
    out = out.astype(np.uint8)
    return out


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH, "gray_01.bmp")
    image = cv.imread(imagePath, cv.IMREAD_GRAYSCALE)
    out = hist_operate(image)

    plt.subplot(1, 2, 1)
    plt.hist(image.ravel(), bins=255, rwidth=0.8, range=(0, 255))
    plt.subplot(1, 2, 2)
    plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))

    cv.imshow("Orginal", image)
    cv.imshow("NewImage", out)
    plt.show()
    cv.waitKey(0)

23. 直方图均衡化(Histogram Equalization)

直方图均衡化是使得直方图变得平坦的操作,是不需要计算上面的问题中的平均值,标准差等数据使得直方图变得均衡的操作.
均衡化的操作由以下的式子定义. S是总的像素数,Zmax是像素点的最大取值(在这里是255);h(z)表示取值为z的累积分布函数;

opencv 怎么分离出水印 opencvfindhomography_直方图_02


代码示例:

# @Time   : 2022/6/11 11:49
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
import matplotlib.pyplot as plt

# histogram equalization
def hist_equal(image, zMax=255):
    H, W = image.shape[:2]
    S = H * W
    out = image.copy()
    sumH = 0
    for i in range(1, 255):
        ind = np.where(image == i)
        sumH += len(image[ind]) 
        zPrime = zMax / S * sumH
        out[ind] = zPrime

    out = out.astype(np.uint8)
    return out

if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)
    histEqual = hist_equal(imageOriginal)

    plt.subplot(1,2,1)
    plt.hist(imageOriginal.ravel(),bins=255,rwidth=0.8,range = (0,255))
    plt.subplot(1,2,2)
    plt.hist(histEqual.ravel(),bins=255,rwidth=0.8,range=(0,255))
    plt.show(())

    cv.imshow("Original",imageOriginal)
    cv.imshow("HistEqual",histEqual)
    cv.waitKey(0)

24. 伽马校正(Gamma Correction)

伽马校正用来对照相机等电子设备传感器的非线性光电转换特性进行校正.如果图像原样显示在显示器等上,画面就会显得很暗.伽马校正通过预先增大RGB的值来排除显示器的影响,达到图像修正的目的.

由于下式引起非线性变换,在该式中,x被归一化,限定在[0,1]范围内.c是常数,g为伽马变量(通常取2.2):

opencv 怎么分离出水印 opencvfindhomography_直方图_03

# @Time   : 2022/6/11 11:58
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *

# gamma correction
def gamma_correction(image,c=1,g=2.2):
    out = image.copy()
    out  = out / 255
    out = (1/c * out) ** (1/g)

    out *= 255
    out = out.astype(np.uint8)
    return out

if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)
    gammaRes = gamma_correction(imageOriginal,1,2.2)
    cv.imshow("Original",imageOriginal)
    cv.imshow("GammaRes",gammaRes)
    cv.waitKey(0)

25. 最近邻插值 (Nearest-neighbor Interpolation)

使用最近邻插值算法将图像放大1.5倍

最近邻插值在图像放大时补充的像素取最邻近的像素的值.由于方法简单,所以处理速度很快,但是放大图像画质劣化明显.
使用下面的公式放大图像吧! I'为放大后图像,I为发达前图像,a为放大率,方括号是四色五入操作:

opencv 怎么分离出水印 opencvfindhomography_计算机视觉_04

# @Time   : 2022/6/11 15:43
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *


def nearest_interpolate(image, ax=1.0, ay=1.0):
    H, W, C = image.shape

    aH = int(ay * H)
    aW = int(ax * W)

    y = np.arange(aH).repeat(aW).reshape(aH, -1)
    x = np.tile(np.arange(aW), (aH, 1))
    y = np.round(y / ay).astype(np.int64)
    x = np.round(x / ax).astype(np.int64)

    out = image[y, x]

    out = out.astype(np.uint8)

    return out


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH, "color_02.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_COLOR)
    cv.imshow("Original", imageOriginal)
    out = nearest_interpolate(imageOriginal, ax=1.5, ay=1.5)

    cv.imshow("NearestInterpolation",out)
    cv.waitKey(0)