DIP_UN_07

文章目录

  • 课程目标
  • 一、噪声的几种类型
  • 二、自适应均值滤波和算数均值滤波
  • 三、中值滤波和自适应中值滤波
  • 四、逆滤波和维纳滤波
  • 五、图像复原综合
  • 六、一个画笔修复的例子
  • 七、几何校正的简单例子
  • 八、陷波滤波器处理周期噪声的例子


课程目标

了解和掌握图像退化的原因,了解图像退化的基本模型,能够掌握空间域及变换域的图像复原的基本方法、几何失真校正的的基本方法等。


一、噪声的几种类型

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


def normalize(mask):
    return (mask - mask.min()) / (mask.max() - mask.min())


# 高斯噪声PDF
def gauss_pdf(z):
    mean = np.mean(z)
    sigma = np.std(z)
    gauss = (1 / (np.sqrt(2 * np.pi * sigma))) * np.exp(-((z - mean) ** 2) / (2 * sigma))
    return gauss


# 高斯噪声
def add_gaussian_noise(img, mu=0, sigma=0.1):
    """
    add gaussian noise for image
    param:  img:       input image, dtype=uint8
    param:  mean:      noise mean
    param:  sigma:     noise sigma
    return: image_out: image with gaussian noise
    """
    image = np.array(img / 255, dtype=float)
    noise = np.random.normal(mu, sigma, image.shape)

    image_out = image + noise
    image_out = np.uint8(normalize(image_out) * 255)

    return image_out


# 瑞利噪声PDF
def rayleigh_pdf(z, a=3, b=2):
    assert b != 0, "b is denominator, cannot be zero!!!"
    output = (2 / b) * (z - a) * np.exp(-((z - a)**2 )/b)
    output = np.where(z > a, output, 0)
    return output


# 瑞利噪声
def add_rayleigh_noise(img, a=3):
    """
    add rayleigh noise for image
    param: img: input image, dtype=uint8
    param: mean: noise mean
    param: sigma: noise sigma
    return: image_out: image with rayleigh noise
    """
    image = np.array(img / 255, dtype=float)

    # ============== numpy.random.rayleigh======
    noise = np.random.rayleigh(a, size=image.shape)
    noise = noise / noise.max()

    image_out = image + noise
    image_out = np.uint8(normalize(image_out) * 255)

    return image_out


# 爱尔兰(伽马)噪声PDF
def ireland_pdf(z, a=2, b=1):
    """
    create ireland PDF, math $$P(z) = \begin{cases} \frac{a^bz^{b-1}}{(b-1)!}e^{-az}, & z\geq 0 \\ 0, & z < 0 \end{cases}$$
    param: z: input grayscale value of iamge
    param: a: float, a > b
    param: b: uint,
    """
    ireland = (a ** b * z ** (b - 1) / np.math.factorial(b - 1)) * np.exp(- a * z)
    ireland = np.where(z >= 0, ireland, 0)

    return ireland


# 爱尔兰(伽马)噪声
def add_gamma_noise(img, scale=1):
    """
    add gamma noise for image
    param: img: input image, dtype=uint8
    param: mean: noise mean
    param: sigma: noise sigma
    return: image_out: image with gamma noise
    """
    image = np.array(img / 255, dtype=float)

    noise = np.random.gamma(shape=1, scale=scale, size=image.shape)
    noise = noise / noise.max()

    image_out = image + noise
    image_out = np.uint8(normalize(image_out) * 255)

    return image_out


# 指数噪声PDF
def exponential_pdf(z, a=1):
    """
    create exponential PDF, math $$P(z) = \begin{cases} ae^{-az}, & z\geq 0 \\ 0, & z < 0 \end{cases}$$
    param: z: input grayscale value of iamge
    param: a: float,
    """
    exp = a * np.exp(-a * z)
    exp = np.where(z >= 0, exp, 0)

    return exp


# 指数噪声
def add_exponent_noise(img, scale=1.0):
    """
    add gamma noise for image
    param: img: input image, dtype=uint8
    param: mean: noise mean
    param: sigma: noise sigma
    return: image_out: image with gamma noise
    """
    image = np.array(img / 255, dtype=float)

    noise = np.random.exponential(scale=scale, size=image.shape)
    noise = noise / noise.max()

    image_out = image + noise
    image_out = np.uint8(normalize(image_out) * 255)

    return image_out


# 均匀噪声PDF
def average_pdf(z, a=1, b=2):
    """
    create average PDF, math $$P(z) = \begin{cases}\frac{1}{b-a}, & a\leq z \leq b \\ 0, & \text{other}\end{cases} $$
    param: z: input grayscale value of iamge
    param: a: uint, if image value. it could be float as well.
    param: b: uint, if image value. b > a, it could be float as well.
    """
    assert b > a, "b must greater than a"

    average = 1 / (b - a)
    average = np.where(z < a, 0, average)
    average = np.where(z > b, 0, average)

    return average


# 均匀噪声
def add_average_noise(img, mean=0, sigma=800):
    """
    add average noise for image
    param:  img:     input image, dtype=uint8
    param:  mean:     noise mean
    param:  sigma:     noise sigma
    return: image_out: image with average noise
    """
    image = np.array(img / 255, dtype=float)

    a = 2 * mean - np.sqrt(12 * sigma)
    b = 2 * mean + np.sqrt(12 * sigma)

    noise = np.random.uniform(a, b, image.shape)
    noise = noise / noise.max()
    image_out = image + noise

    image_out = np.uint8(normalize(image_out) * 255)

    return image_out


# 椒盐噪声PDF
def salt_pepper_pdf(ps=0.1, pp=0.1):
    """
    create salt and pepper PDF, math $$P(z) = \begin{cases} P_s, & z = 2^k -1 \\ P_p, & z=0 \\ 1-(P_s + P_p), & z=V \end{cases}$$
    param: z: input grayscale value of iamge
    param: v:  float, while z = v, probability of other values
    param: ps: float, probability of the salt
    param: pp: float, probability of the pepper
    """
    salt_pepper = np.zeros([3])
    salt_pepper[0] = ps
    salt_pepper[2] = pp
    salt_pepper[1] = 1 - (ps + pp)
    return salt_pepper


# 椒盐噪声
def add_salt_pepper(img, ps=0.01, pp=0.01):
    """
    add salt pepper noise to image
    param: img: input image, uint8 [0, 255]
    param: ps:  probability of salt noise, which is white noise, default is 0.01
    param: pp:  probability of peper noise, which is black noise, default is 0.01
    return image with salt pepper noise, [0, 255]
    """
    h, w = img.shape[:2]
    mask = np.random.choice((0, 0.5, 1), size=(h, w), p=[pp, (1 - ps - pp), ps])

    img_out = img.copy()
    img_out[mask == 1] = 255
    img_out[mask == 0] = 0
    return img_out


# 椒盐噪声
def add_salt_pepper_1(img, prob):
    output = np.zeros(img.shape, np.uint8)
    thres = 1 - prob

    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            rdn = np.random.random()
            if rdn < prob:
                output[i][j] = 0
            elif rdn > thres:
                output[i][j] = 255
            else:
                output[i][j] = img[i][j]
    return output


# 一些重要的噪声

a = 2
b = 8

ps = 0.05   # 椒盐噪声ps
pp = 0.02   # 椒盐噪声pp

z = np.linspace(0, 10, 200)

img_ori = cv2.imread("D:\\DIP_Photo\\Fig0503 (original_pattern).tif", 0)

img_gauss = add_gaussian_noise(img_ori, mu=0, sigma=0.05)
img_rayleigh = add_rayleigh_noise(img_ori, a=1)
img_gamma = add_gamma_noise(img_ori, scale=2)
img_exponent = add_exponent_noise(img_ori, scale=3)
img_average = add_average_noise(img_ori, mean=10, sigma=1.5)
img_salt_pepper = add_salt_pepper(img_ori, ps=ps, pp=pp)

show_list = ['img_gauss', 'img_rayleigh', 'img_gamma', 'img_exponent', 'img_average', 'img_salt_pepper']

fig = plt.figure(figsize=(12, 16))

for i in range(len(show_list)):
    if i >= 3:
        # 显示图像
        ax = fig.add_subplot(4, 3, i + 3 + 1)
        ax.imshow(eval(show_list[i]), 'gray'), ax.set_xticks([]), ax.set_yticks([]), ax.set_title(
            show_list[i].split('_')[-1])
        # 对应图像的直方图
        ax = fig.add_subplot(4, 3, i + 1 + 6)
        hist, bins = np.histogram(eval(show_list[i]).flatten(), bins=255, range=[0, 255], density=True)
        bar = ax.bar(bins[:-1], hist[:]), ax.set_xticks([]), ax.set_yticks([]),
    else:
        # 显示图像
        ax = fig.add_subplot(4, 3, i + 1)
        ax.imshow(eval(show_list[i]), 'gray'), ax.set_xticks([]), ax.set_yticks([]), ax.set_title(
            show_list[i].split('_')[-1])
        # 对应图像的直方图
        ax = fig.add_subplot(4, 3, i + 1 + 3)
        hist, bins = np.histogram(eval(show_list[i]).flatten(), bins=255, range=[0, 255], density=True)
        bar = ax.bar(bins[:-1], hist[:]), ax.set_xticks([]), ax.set_yticks([]),

plt.tight_layout()
plt.show()

二、自适应均值滤波和算数均值滤波

代码如下(示例):

# 自适应均值滤波和算术均值滤波
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image


def mean_filter(src_image, kernel_size=3):
    """The arithmetic average filter"""
    edge_size = int(kernel_size / 2)
    padded_img = np.pad(src_image, edge_size, 'edge')

    height, width = src_image.shape

    src_after_filter = np.zeros_like(src_image, dtype="float64")

    for i in range(height):
        for j in range(width):
            box = padded_img[i:i + kernel_size, j:j + kernel_size]
            src_after_filter[i, j] = np.mean(box)

    return src_after_filter


def self_adaptaion_mean_filter(src_image, kernel_size=3, variance=1000):
    """self adaptaion mean filter"""
    edge_size = int(kernel_size / 2)
    padded_img = np.pad(src_image, edge_size, 'edge')

    height, width = src_image.shape

    src_after_filter = np.zeros_like(src_image, dtype="float64")

    for i in range(height):
        for j in range(width):
            box = padded_img[i:i + kernel_size, j:j + kernel_size]
            box_mean = np.mean(box)
            box_var = np.var(box)
            src_after_filter[i, j] = \
                src_image[i, j] - (variance / box_var) * (src_image[i, j] - box_mean)

    return src_after_filter


def main(img_path):
    src = np.array(Image.open(img_path).convert("L"))
    noise = np.random.normal(0, 15, size=src.shape)
    noise_src = src + noise

    img_mean_filter = mean_filter(noise_src, 7)
    img_self_adap_mean_filter = self_adaptaion_mean_filter(noise_src, 7, 225)

    img_list = [src, noise_src, img_mean_filter, img_self_adap_mean_filter]
    img_name = ["原图像", "被加性高斯噪声污染的图像", "7×7算术均值滤波", "7×7自适应均值滤波"]

    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    _, axs = plt.subplots(2, 2, figsize=(12, 12))

    for i in range(2):
        for j in range(2):
            axs[i][j].imshow(img_list[i * 2 + j], cmap='gray')
            axs[i][j].set_title(img_name[i * 2 + j])
            axs[i][j].axes.get_xaxis().set_visible(False)
            axs[i][j].axes.get_yaxis().set_visible(False)

    plt.show()


if __name__ == '__main__':
    main("D:\\DIP_Photo\\Cameraman.tif")

三、中值滤波和自适应中值滤波

代码如下(示例):

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import sys


def salt(image, prob):
    """prob:Noise Scale"""
    output = np.zeros(image.shape, np.float64)
    prob_other = 1 - prob
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            rdn = np.random.random()
            if rdn < prob:
                output[i][j] = 0
            elif rdn > prob_other:
                output[i][j] = 255
            else:
                output[i][j] = image[i][j]
    return output


def median_filter(src_image, kernel_size):
    """Median filter"""
    edge_size = int(kernel_size / 2)
    padded_img = np.pad(src_image, edge_size, 'edge')

    height, width = src_image.shape

    src_after_filter = np.zeros_like(src_image, dtype="float64")

    for i in range(height):
        for j in range(width):
            box = padded_img[i:i + kernel_size, j:j + kernel_size]
            src_after_filter[i, j] = np.median(box)

    return src_after_filter


def self_adaptation_median_filter(src_image, kernel_size, output):
    """self-adaptation median filter"""

    height, width = src_image.shape

    num = height * width
    loc = 0

    src_after_filter = np.zeros_like(src_image, dtype="float64")

    for i in range(height):
        for j in range(width):
            rst = filter_process(src_image, kernel_size, i, j, 7)
            src_after_filter[i][j] = rst
            loc = loc + 1
            count = loc / num * 100
            output.write(f'\rcomplete percent:{count:.0f}')

    return src_after_filter


def filter_process(src_image, kernel_size, i, j, s_max=7):
    edge_size = int(kernel_size / 2)
    padded_img = np.pad(src_image, edge_size, 'edge')

    box = padded_img[i:i + kernel_size, j:j + kernel_size]
    z_min = np.min(box)
    z_max = np.max(box)
    z_med = np.median(box)
    z_xy = src_image[i, j]

    rst = a_process(src_image, kernel_size, i, j, s_max, z_xy, z_min, z_max, z_med)

    return rst


def a_process(src_image, kernel_size, i, j, s_max, z_xy, z_min, z_max, z_med):
    A1 = z_med - z_min
    A2 = z_med - z_max

    if A1 > 0 and A2 < 0:
        return b_process(z_xy, z_min, z_max, z_med)
    elif (kernel_size + 2) <= s_max:
        return filter_process(src_image, kernel_size + 2, i, j, s_max)
    else:
        return z_med


def b_process(z_xy, z_min, z_max, z_med):
    B1 = z_xy - z_min
    B2 = z_xy - z_max

    if B1 > 0 and B2 < 0:
        return z_xy
    else:
        return z_med


def add_noise(src_image, noise_method, prob):
    return noise_method(src_image, prob)


def main(img_path):
    src = np.array(Image.open(img_path).convert("L"))
    noise_src = add_noise(src, salt, 0.1)

    output = sys.stdout

    img_median_filter = median_filter(noise_src, 3)
    img_self_adap_median_filter = self_adaptation_median_filter(noise_src, 3, output)

    output.flush()

    img_list = [src, noise_src, img_median_filter, img_self_adap_median_filter]
    img_name = ["原图像", "被椒盐噪声污染的图像", "3×3中值滤波", "自适应中值滤波"]

    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    _, axs = plt.subplots(2, 2, figsize=(12, 12))

    for i in range(2):
        for j in range(2):
            axs[i][j].imshow(img_list[i * 2 + j], cmap='gray')
            axs[i][j].set_title(img_name[i * 2 + j])
            axs[i][j].axes.get_xaxis().set_visible(False)
            axs[i][j].axes.get_yaxis().set_visible(False)

    plt.show()


if __name__ == '__main__':
    main("D:\\DIP_Photo\\Cameraman.tif")

四、逆滤波和维纳滤波

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image


def motion_process(height, weight, k=0.001):
    h_uv = np.zeros((height, weight), dtype='complex128')
    for u in range(height):
        for v in range(weight):
            q = np.power((u ** 2 + v ** 2), (5.0 / 6.0))
            h_uv[u][v] = np.exp(-(k * q))
    return h_uv


def blur_noise(src, h_uv):
    noise = np.random.normal(0, 1, size=src.shape)
    f_uv = np.fft.fft2(src)
    arr = np.multiply(f_uv, h_uv) + noise
    return arr, noise


def winner(src, h_uv, k=0.001):
    p_uv = np.conj(h_uv) / (np.abs(h_uv) ** 2 + 0.00005*k)
    rst = np.multiply(src, p_uv)
    return np.abs(np.fft.ifft2(rst))


def inv_filter(src, h_uv):
    p_uv = 1 / h_uv
    rst = np.multiply(src, p_uv)
    return np.abs(np.fft.ifft2(rst))


def main(img_path):
    src = np.array(Image.open(img_path).convert("L"))
    height, weight = src.shape
    h_uv = motion_process(height, weight, k=0.001)
    noise_src, noise = blur_noise(src, h_uv)
    mov_noi_src = np.abs(np.fft.ifft2(noise_src))
    k = np.power(np.abs(np.fft.fft2(noise)), 2) / np.power(np.abs(np.fft.fft2(src)), 2)

    src_processed_inv_filter = inv_filter(noise_src, h_uv)
    src_processed_winner = winner(noise_src, h_uv, k)

    img_list = [src, mov_noi_src, src_processed_inv_filter, src_processed_winner]
    img_name = ["原图像", "运动模糊+高斯噪声", "逆滤波", "维纳滤波"]

    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    _, axs = plt.subplots(2, 2, figsize=(12, 12))

    for i in range(2):
        for j in range(2):
            axs[i][j].imshow(img_list[i * 2 + j], cmap='gray')
            axs[i][j].set_title(img_name[i * 2 + j])
            axs[i][j].axes.get_xaxis().set_visible(False)
            axs[i][j].axes.get_yaxis().set_visible(False)

    plt.show()


if __name__ == '__main__':
    main("D:\\DIP_Photo\\Cameraman.tif")

五、图像复原综合

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from numpy import fft


def motion_process(image_size, motion_angle):
    PSF = np.zeros(image_size)
    center_position = (image_size[0] - 1) / 2

    slope_tan = np.tan(motion_angle * np.pi / 180)
    slope_cot = 1 / slope_tan
    if slope_tan <= 1:
        for i in range(15):
            offset = round(i * slope_tan)  # ((center_position-i)*slope_tan)
            PSF[int(center_position + offset), int(center_position - offset)] = 1
        return PSF / PSF.sum()  # 对点扩散函数进行归一化亮度
    else:
        for i in range(15):
            offset = round(i * slope_cot)
            PSF[int(center_position - offset), int(center_position + offset)] = 1
        return PSF / PSF.sum()


def psf2otf(psf, outSize):
    psfSize = np.array(psf.shape)
    outSize = np.array(outSize)
    padSize = outSize - psfSize
    psf = np.pad(psf, ((0, padSize[0]), (0, padSize[1])), 'constant')
    for i in range(len(psfSize)):
        psf = np.roll(psf, -int(psfSize[i] / 2), i)
    otf = np.fft.fftn(psf)
    nElem = np.prod(psfSize)
    nOps = 0
    for k in range(len(psfSize)):
        nffts = nElem / psfSize[k]
        nOps = nOps + psfSize[k] * np.log2(psfSize[k]) * nffts
    if np.max(np.abs(np.imag(otf))) / np.max(np.abs(otf)) <= nOps * np.finfo(np.float32).eps:
        otf = np.real(otf)
    return otf


def CLSF(blurred, PSF, gamma=0.05):
    PF = psf2otf(PSF,blurred.shape)
    size = blurred.shape
    kernel = np.array([[0, -1, 0],
                       [-1, 4, -1],
                       [0, -1, 0]])

    PF_kernel = psf2otf(kernel, size)
    IF_noisy = fft.fft2(blurred)

    numerator = np.conj(PF)
    denominator = PF ** 2 + gamma * (PF_kernel ** 2)
    CLSF_deblurred = fft.ifft2(numerator * IF_noisy / denominator)
    CLSF_deblurred = np.real(CLSF_deblurred)
    return CLSF_deblurred


def inverse(blurred_image, PSF, eps):  # 逆滤波
    input_fft = fft.fft2(blurred_image)
    PSF_fft = fft.fft2(PSF) + eps  # 噪声功率,这是已知的,考虑epsilon
    result = fft.ifft2(input_fft / PSF_fft)  # 计算F(u,v)的傅里叶反变换
    result = np.abs(fft.fftshift(result))
    return result


def wiener(blurred_img, PSF, eps, k=0.01):  # 维纳滤波,K=0.01
    input_fft = fft.fft2(blurred_img)
    PSF_fft = fft.fft2(PSF) + eps
    PSF_fft_1 = np.conj(PSF_fft) / (np.abs(PSF_fft) ** 2 + k)
    result = fft.ifft2(input_fft * PSF_fft_1)
    result = np.abs(fft.fftshift(result))
    return result


def make_blurred(image, PSF, eps):
    input_fft = fft.fft2(image)  # 进行二维数组的傅里叶变换
    PSF_fft = fft.fft2(PSF) + eps
    blurred = fft.ifft2(input_fft * PSF_fft)
    blurred = np.abs(fft.fftshift(blurred))
    return blurred


def main(img_path):
    img = np.array(Image.open(img_path).convert("L"))

    img_size = img.shape
    PSF = motion_process(img_size, 60)

    blurred = make_blurred(img, PSF, 1e-3)
    blurred_inv = inverse(blurred, PSF, 1e-3)
    blurred_wiener = wiener(blurred, PSF, 1e-3, 0.01)
    blurred_CLSF = CLSF(blurred, PSF)

    blurred_noise = make_blurred(img, PSF, 1e-3) + np.random.normal(0, 5, img_size)
    blurred_noise_inv = inverse(blurred_noise, PSF, 1e-3)
    blurred_noise_wiener = wiener(blurred_noise, PSF, 1e-3, 0.01)
    blurred_noise_CLSF = CLSF(blurred_noise, PSF,0.03)

    img_list = [img, blurred, blurred_inv, blurred_wiener, blurred_CLSF,
                blurred_noise, blurred_noise_inv,blurred_noise_wiener, blurred_noise_CLSF]
    img_name = ["原图像", "运动模糊", "逆滤波", "维纳滤波", "约束最小二乘方",
                "运动模糊(噪声)", "逆滤波(噪声)", "维纳滤波(噪声)", "约束最小二乘方(噪声)"]

    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    _, axs = plt.subplots(3, 3, figsize=(12, 12))

    for i in range(3):
        for j in range(3):
            axs[i][j].imshow(img_list[i * 3 + j], cmap='gray')
            axs[i][j].set_title(img_name[i * 3 + j])
            axs[i][j].axes.get_xaxis().set_visible(False)
            axs[i][j].axes.get_yaxis().set_visible(False)

    plt.show()


if __name__ == '__main__':
    main("D:\\DIP_Photo\\Cameraman.tif")

六、一个画笔修复的例子

import numpy as np
import cv2 as cv
import time


# opencv Class for Mouse (Version for python) set mouse...
class Sketcher:
    def __init__(self, windowname, dests, colors_func):
        self.prev_point = None
        self.windowname = windowname
        # dests is a set of images: copy & mask
        self.dests = dests
        self.colors_func = colors_func
        self.dirty = False
        self.show()
        cv.setMouseCallback(self.windowname, self.on_mouse)

    def show(self):
        cv.imshow(self.windowname, self.dests[0])
        cv.imshow(self.windowname + ":mask", self.dests[1])

    # on mouse function
    def on_mouse(self, event, x, y, flags, param):
        # point store the current position of the mouse
        point = (x, y)
        if event == cv.EVENT_LBUTTONDOWN:
            # assignment of previous point
            self.prev_point = point
        elif event == cv.EVENT_LBUTTONUP:
            self.prev_point = None
        # cv.EVENT_FLAG_LBUTTON & flags 代表按住左键拖拽
        if self.prev_point and flags & cv.EVENT_FLAG_LBUTTON:
            # zip 把前后参数打包为元组
            for dst, color in zip(self.dests, self.colors_func()):
                cv.line(dst, self.prev_point, point, color, 5)
        # Record this dirt
        self.dirty = True
        self.prev_point = point
        self.show()


def main():
    print("Usage: python inpaint ")
    print("Keys: ")
    print("t - inpaint using FMM")  # Fast Marching method
    print("n - inpaint using NS technique")
    print("r - reset the inpainting mask")
    print("ESC - exit")

    # Read image in color mode
    img = cv.imread("D:\\DIP_Photo\\Snowtext.jpg", cv.IMREAD_COLOR)

    # Return error if failed to read the image
    if img is None:
        print("Failed to read the image")
        return

    # Create the copy of the original image
    img_mask = img.copy()

    # Create a black mask of the image
    inpaintMask = np.zeros(img.shape[:2], np.uint8)
    # Create a Sketch
    # dests= img_mask, inpaintMask
    # color_func is a tuple : white with BGR and white on gray
    sketch = Sketcher('image', [img_mask, inpaintMask], lambda: ((255, 255, 255), 255))

    while True:
        ch = cv.waitKey()
        # Esc
        if ch == 27:
            break

        if ch == ord('t'):
            t1 = time.time()
            res = cv.inpaint(src=img_mask, inpaintMask=inpaintMask, inpaintRadius=3, flags=cv.INPAINT_TELEA)
            res = np.hstack((img, res))
            t2 = time.time()
            # print("Time: FMM = {} ms".format((t2 - t1) * 1000))
            cv.imshow('Inpaint with FMM', res)
            # cv.imwrite("FMM-Snow.png", res)

        if ch == ord('n'):
            t1 = time.time()
            res = cv.inpaint(src=img_mask, inpaintMask=inpaintMask, inpaintRadius=3, flags=cv.INPAINT_NS)
            res = np.hstack((img, res))
            t2 = time.time()
            cv.imshow('Inpaint Output using NS Technique', res)
            # cv.imwrite("NS-Snow.png", res)
        # type r to reset the image
        if ch == ord('r'):
            # The reason for which we copied image
            img_mask[:] = img
            inpaintMask[:] = 0
            sketch.show()

    print('Completed')


if __name__ == '__main__':
    main()
    cv.destroyAllWindows()

七、几何校正的简单例子

import cv2 as cv
import numpy as np

img = cv.imread("D:\\DIP_Photo\\Casio.jpg")

width, height = 320, 480

pts1 = np.float32([[26, 177], [300, 66], [207, 613], [473, 504]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
matrix = cv.getPerspectiveTransform(pts1, pts2)

imgOutput = cv.warpPerspective(img, matrix, (width, height))

cv.imshow("ImgOutput", imgOutput)
cv.imshow("ImgWarp", img)

cv.waitKey()
cv.destroyAllWindows()

八、陷波滤波器处理周期噪声的例子

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


# 理想陷波滤波器
def idea_notch_resistant_filter(source, uk, vk, radius=5):
    """
    create idea notch resistant filter
    param: source: input, source image
    param: uk:     input, int, center of the height
    param: vk:     input, int, center of the width
    param: radius: input, the radius of the lowest value, greater value, bigger blocker out range, if the radius is 0, then all
                   value is 0
    return a [0, 1] value filter
    """
    M, N = source.shape[1], source.shape[0]

    u = np.arange(M)
    v = np.arange(N)

    u, v = np.meshgrid(u, v)

    DK = np.sqrt((u - M // 2 - uk) ** 2 + (v - N // 2 - vk) ** 2)
    D_K = np.sqrt((u - M // 2 + uk) ** 2 + (v - N // 2 + vk) ** 2)
    D0 = radius
    k_1 = DK.copy()
    k_2 = D_K.copy()

    k_1[DK > D0] = 1
    k_1[DK <= D0] = 0

    k_2[D_K > D0] = 1
    k_2[D_K <= D0] = 0

    kernel = k_1 * k_2

    return kernel


# 高斯陷波滤波器
def gauss_notch_resistant_filter(source, uk, vk, radius=5):
    """
    create gauss low pass filter
    param: source: input, source image
    param: uk:     input, int, center of the height
    param: vk:     input, int, center of the width
    param: radius: input, the radius of the lowest value, greater value, bigger blocker out range, if the radius is 0, then all
                   value is 0
    return a [0, 1] value filter
    """
    M, N = source.shape[1], source.shape[0]

    u = np.arange(M)
    v = np.arange(N)

    u, v = np.meshgrid(u, v)

    DK = np.sqrt((u - M // 2 - uk) ** 2 + (v - N // 2 - vk) ** 2)
    D_K = np.sqrt((u - M // 2 + uk) ** 2 + (v - N // 2 + vk) ** 2)
    D0 = radius

    k_1 = 1 - np.exp(- (DK ** 2) / (D0 ** 2))
    k_2 = 1 - np.exp(- (D_K ** 2) / (D0 ** 2))

    kernel = k_1 * k_2
    return kernel


# 巴特沃斯陷波滤波器
def butterworth_notch_resistant_filter(img, uk, vk, radius=10, n=1):
    """
    create butterworth notch resistant filter, equation 4.155
    param: img:    input, source image
    param: uk:     input, int, center of the height
    param: vk:     input, int, center of the width
    param: radius: input, int, the radius of circle of the band pass filter, default is 10
    param: w:      input, int, the width of the band of the filter, default is 5
    param: n:      input, int, order of the butter worth fuction,
    return a [0, 1] value butterworth band resistant filter
    """
    M, N = img.shape[1], img.shape[0]

    u = np.arange(M)
    v = np.arange(N)

    u, v = np.meshgrid(u, v)

    DK = np.sqrt((u - M // 2 - uk) ** 2 + (v - N // 2 - vk) ** 2)
    D_K = np.sqrt((u - M // 2 + uk) ** 2 + (v - N // 2 + vk) ** 2)
    D0 = radius
    kernel = (1 / (1 + (D0 / (DK + 1e-5)) ** n)) * (1 / (1 + (D0 / (D_K + 1e-5)) ** n))

    return kernel


def plot_3d(ax, x, y, z, cmap):
    ax.plot_surface(x, y, z, antialiased=True, shade=True, cmap=cmap)
    ax.view_init(20, -20), ax.grid(b=False), ax.set_xticks([]), ax.set_yticks([]), ax.set_zticks([])


def normalize(mask):
    return (mask - mask.min()) / (mask.max() - mask.min())


def add_sin_noise(img, scale=1, angle=0):
    """
    add sin noise for image
    param: img: input image, 1 channel, dtype=uint8
    param: scale: sin scaler, smaller than 1, will enlarge, bigger than 1 will shrink
    param: angle: angle of the rotation
    return: output_img: output image is [0, 1] image which you could use as mask or any you want to
    """

    height, width = img.shape[:2]  # original image shape

    # convert all the angle
    if int(angle / 90) % 2 == 0:
        rotate_angle = angle % 90
    else:
        rotate_angle = 90 - (angle % 90)

    rotate_radian = np.radians(rotate_angle)    # convert angle to radian

    # get new image height and width
    new_height = int(np.ceil(height * np.cos(rotate_radian) + width * np.sin(rotate_radian)))
    new_width = int(np.ceil(width * np.cos(rotate_radian) + height * np.sin(rotate_radian)))

    # if new height or new width less than orginal height or width, the output image will be not the same shape as input, here set it right
    if new_height < height:
        new_height = height
    if new_width < width:
        new_width = width

    # meshgrid
    u = np.arange(new_width)
    v = np.arange(new_height)
    u, v = np.meshgrid(u, v)

    # get sin noise image, you could use scale to make some difference, better you could add some shift
    #     noise = abs(np.sin(u * scale))
    noise = 1 - np.sin(u * scale)

    # here use opencv to get rotation, better write yourself rotation function
    C1 = cv2.getRotationMatrix2D((new_width /2.0, new_height /2.0), angle, 1)
    new_img = cv2.warpAffine(noise, C1, (int(new_width), int(new_height)), borderValue=0)

    # ouput image should be the same shape as input, so caculate the offset the output image and the new image
    # I make new image bigger so that it will cover all output image

    offset_height = abs(new_height - height) // 2
    offset_width = abs(new_width - width) // 2
    img_dst = new_img[offset_height:offset_height + height, offset_width:offset_width +width]
    output_img = normalize(img_dst)

    return output_img


def spectrum_fft(fft):
    """
    return FFT spectrum
    """
    return np.sqrt(np.power(fft.real, 2) + np.power(fft.imag, 2))


# 理想、高斯、巴特沃斯陷波滤波器
img_temp = np.zeros([256, 256])

INRF = idea_notch_resistant_filter(img_temp, radius=20, uk=30, vk=80)
GNRF = gauss_notch_resistant_filter(img_temp, radius=20, uk=30, vk=80)
BNRF = butterworth_notch_resistant_filter(img_temp, radius=20, uk=30, vk=80, n=5)

# 用来绘制3D图
M, N = img_temp.shape[1], img_temp.shape[0]
u = np.arange(M)
v = np.arange(N)
u, v = np.meshgrid(u, v)

fig = plt.figure(figsize=(12, 4))
ax_1 = fig.add_subplot(1, 3, 1, projection='3d')
plot_3d(ax_1, u, v, INRF, cmap=cm.plasma)

ax_1 = fig.add_subplot(1, 3, 2, projection='3d')
plot_3d(ax_1, u, v, GNRF, cmap=cm.PiYG)

ax_1 = fig.add_subplot(1, 3, 3, projection='3d')
plot_3d(ax_1, u, v, BNRF, cmap=cm.PiYG)
plt.tight_layout()
plt.show()


# 陷波滤波器处理周期噪声
img_ori = cv2.imread('D:\\DIP_Photo\\Fig0507(a)(ckt-board-orig).tif', 0)  # 直接读为灰度图像

# 正弦噪声
noise = add_sin_noise(img_ori, scale=0.35, angle=-20)
img = np.array(img_ori / 255, np.float32)
img_noise = img + noise
img_noise = np.uint8(normalize(img_noise) * 255)

# 频率域中的其他特性
# FFT
img_fft = np.fft.fft2(img_noise.astype(np.float32))
# 中心化
fshift = np.fft.fftshift(img_fft)  # 将变换的频率图像四角移动到中心
# 中心化后的频谱
spectrum_fshift = spectrum_fft(fshift)
spectrum_fshift_n = np.uint8(normalize(spectrum_fshift) * 255)

# 对频谱做对数变换
spectrum_log = np.log(1 + spectrum_fshift)

BNRF = butterworth_notch_resistant_filter(img_ori, radius=5, uk=25, vk=10, n=4)

f1shift = fshift * (BNRF)
f2shift = np.fft.ifftshift(f1shift)  # 对新的进行逆变换
img_new = np.fft.ifft2(f2shift)
img_new = np.abs(img_new)

plt.figure(figsize=(9, 9))
plt.subplot(221), plt.imshow(img_noise, 'gray'), plt.title('With Sine noise'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(spectrum_log, 'gray'), plt.title('Spectrum'), plt.xticks([]), plt.yticks([])
# 在图像上加上箭头
plt.arrow(180, 180, 25, 30, width=5, length_includes_head=True, shape='full')
plt.arrow(285, 265, -25, -30, width=5, length_includes_head=True, shape='full')

plt.subplot(223), plt.imshow(BNRF, 'gray'), plt.title('Spectrum'), plt.xticks([]), plt.yticks([])
# 在图像上加上箭头
plt.arrow(180, 180, 25, 30, width=5, length_includes_head=True, shape='full')
plt.arrow(285, 265, -25, -30, width=5, length_includes_head=True, shape='full')

plt.subplot(224), plt.imshow(img_new, 'gray'), plt.title('Spectrum'), plt.xticks([]), plt.yticks([])

plt.tight_layout()
plt.show()


# 陷波滤波器提取周期噪声
img_ori = cv2.imread('D:\\DIP_Photo\\Fig0507(a)(ckt-board-orig).tif', 0) #直接读为灰度图像

# 正弦噪声
noise = add_sin_noise(img_ori, scale=0.35, angle=-20)
img = np.array(img_ori / 255, np.float32)
img_noise = img + noise
img_noise = np.uint8(normalize(img_noise)*255)

# 频率域中的其他特性
# FFT
img_fft = np.fft.fft2(img_noise.astype(np.float32))
# 中心化
fshift = np.fft.fftshift(img_fft)            # 将变换的频率图像四角移动到中心
# 中心化后的频谱
spectrum_fshift = spectrum_fft(fshift)
spectrum_fshift_n = np.uint8(normalize(spectrum_fshift) * 255)

# 对频谱做对数变换
spectrum_log = np.log(1 + spectrum_fshift)

BNRF = 1 - butterworth_notch_resistant_filter(img_ori, radius=5, uk=25, vk=10, n=4)

f1shift = fshift * (BNRF)
f2shift = np.fft.ifftshift(f1shift)  # 对新的进行逆变换
img_new = np.fft.ifft2(f2shift)
img_new = np.abs(img_new)

plt.figure(figsize=(9, 9))
plt.subplot(221), plt.imshow(img_noise, 'gray'), plt.title('With Sine noise'), plt.xticks([]),plt.yticks([])
plt.subplot(222), plt.imshow(spectrum_log, 'gray'), plt.title('Spectrum'), plt.xticks([]),plt.yticks([])
# 在图像上加上箭头
plt.arrow(180, 180, 25, 30, width=5,length_includes_head=True, shape='full')
plt.arrow(285, 265, -25, -30, width=5,length_includes_head=True, shape='full')

plt.subplot(223), plt.imshow(BNRF, 'gray'), plt.title('Spectrum'), plt.xticks([]),plt.yticks([])
# 在图像上加上箭头
plt.arrow(180, 180, 25, 30, width=5,length_includes_head=True, shape='full')
plt.arrow(285, 265, -25, -30, width=5,length_includes_head=True, shape='full')

plt.subplot(224), plt.imshow(img_new, 'gray'), plt.title('Sine pattern'), plt.xticks([]),plt.yticks([])

plt.tight_layout()
plt.show()


代码示例仅供学生学习参考,如有引用未标注请提醒。

你可能感兴趣的:(数字图像处理,opencv,python,图像处理)