Digital image processing: brightness contrast-geometric transformation-noise processing

Article directory

    • digital image enhancement
      • Brightness and Contrast Conversion
      • geometric transformation
        • Image cropping
        • size transformation
        • image rotation
      • Noise processing
        • add noise
        • Dealing with noise

Digital image enhancement

Brightness and contrast conversion

Image transformation can be divided into the following two types:

  • Point operator: Based on pixel transformation, in this type of image transformation, the corresponding output pixel value is calculated only based on the input pixel value.
  • Neighborhood operator: transform based on image area

Two commonly used point operators use constants to multiply or add point pixel values, which can be expressed as:

g

(

i

,

j

)

=

α

?

f

(

i

,

j

)

+

β

g(i, j) = \alpha * f(i, j) + \beta

g(i,j)=α?f(i,j) + β

Among them, the position of the midpoint of the image is

(

i

,

j

)

(i,j)

(i,j), the α value represents gain, and the β value represents bias. Transforming the brightness and contrast of the image is a point operator. These two parameters can be used to control contrast and brightness respectively. You can adjust the contrast or brightness of the image by adjusting the values of these two parameters. That is, adding a bias constant to each pixel in the original image can make the image brighter. Similarly, multiplying the pixels in the original image by a gain coefficient can adjust the contrast of the image.

Note

The pixel value range of image pixels is [0, 255]. Be sure not to let it overflow. You can use np.clip to truncate it.

Example image:

import cv2
import numpy as np


#Method 1: Implemented based on addWeighted() function
def convert_img1(img, alpha, beta):
    blank = np.zeros(img.shape, img.dtype)
    return cv2.addWeighted(img, alpha, blank, 0, beta)


#Method 2: Manual implementation through for loop
def convert_img2(img, alpha, beta):
    rows, cols, chs = img.shape
    new_img = np.zeros(img.shape, img.dtype)
    for i in range(rows):
        for j in range(cols):
            for k in range(chs):
                new_img[i, j, k] = np.clip(alpha * img[i, j, k] + beta, 0, 255)
    return new_img

img = cv2.imread('woman.png')
cv2.imwrite('convert_img1.jpg', convert_img1(img, 2.2, 50))
cv2.imwrite('convert_img2.jpg', convert_img2(img, 2.2, 50))

In the above code, the parameter list of the addWeighted() function in the function convert_img1() is: [img1,alpha,img2,beta,gamma] means performing the following calculations on the two images:

n

e

w

_

i

m

g

=

a

l

p

h

a

?

i

m

g

1

+

b

e

t

a

?

i

m

g

2

+

g

a

m

m

a

new\_img = alpha * img1 + beta * img2 + gamma

new_img=alpha?img1 + beta?img2 + gamma

The process implemented by the function convert_img2() is to modify the pixel value of the original image through a for loop, which is the same as the process of the function convert_img1(), except that The convert_img1() function calls the addWeighted() function. The pixel values of the image in the img2 parameter are all 0.

Geometric transformation

The geometric transformation of an image refers to an operation that transforms the positions of image pixels in a picture. It maps the coordinate positions in an image to new coordinate positions, that is, changes the spatial position of the pixels, and also changes the spatial position of the pixels. Estimate the pixel value at the new spatial location.

Image cropping

Cut out part of the matrix from the matrix of image data as new image data, thereby realizing cropping of the image.

import cv2
import numpy as np

# Image cropping
img = cv2.imread('woman.png')
print(img.shape)

new_img = img[20:300, 20:400]
cv2.imwrite('crop_img.jpg', new_img)

The process implemented by the above code is to crop the original image from the (20, 20) pixel position to the (300, 400) position. The cropped shape is rectangle.

Size transformation

Modifying the size of the image means modifying the size of the image. OpenCV’s resize() function can achieve this function. When resizing an image, some pixels will inevitably be lost or added. It is recommended to use area interpolation cv2.INTER_AREA when zooming to avoid ripples; it is recommended to use cubic spline interpolation cv2.INTER_CUBIC when zooming in, but its calculation speed is relatively slow . Linear interpolation cv2.INTER_LINEAR can also be used. By default, the interpolation method used by all operations that change the image size is linear interpolation.

# Image scaling
small_resize_img = cv2.resize(img, (200, 200), interpolation=cv2.INTER_AREA)
cv2.imwrite('small_resize.jpg', small_resize_img)

small_resize_img2 = cv2.resize(img, None, fx=0.5, fy=0.6, interpolation=cv2.INTER_AREA) # The width of the image corresponds to the number of columns, and the height corresponds to the number of rows
cv2.imwrite('small_resize2.jpg', small_resize_img2)


Image rotation

Rotation is implemented through the getRotationMatrix2D() function.

# Image rotation
img = cv2.imread('woman.png')
rows, cols, _ = img.shape
rotated_mat = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1) # The first parameter is the rotation center, the second parameter is the rotation angle, and the third parameter is the scale factor after rotation
rotated_img = cv2.warpAffine(img, rotated_mat, dsize=(cols, rows))
cv2.imwrite('rot45.jpg', rotated_img)

Noise processing

Adding an appropriate amount of noise to the training data can make the trained model more robust and help improve the performance of the model. Eliminating noise can increase image quality.

Add noise

There are two common ways to add noise to images:

  • salt and pepper noise
  • Gaussian noise
import cv2
import random
import numpy as np

# Add salt and pepper noise
def salt_and_pepper_noise(img, percentage):
    rows, cols, chs = img.shape
    num = int(percentage * rows * cols)
    for i in range(num):
        x = random.randint(0, rows-1)
        y = random.randint(0, cols-1)
        z = random.randint(0, chs-1)
        if random.randint(0, 1) == 0:
            img[x, y, z] = 0 # black noise
        else:
            img[x, y, z] = 255 # white noise
    return img

# Add Gaussian random noise
def gaussian_noise(img, mu, sigma, delta):
    rows, cols, chs = img.shape
    for i in range(rows):
        for j in range(cols):
            for k in range(chs):
                # Generate random numbers from Gaussian distribution, which must be rounded when added to the original data.
                value = int(img[i, j, k] + delta*random.gauss(mu=mu, sigma=sigma))
                value = np.clip(a_max=255, a_min=0, a=value)
                img[i, j, k] = value
    return img


img = cv2.imread('woman.png')

cv2.imwrite('saltPepper.jpg', salt_and_pepper_noise(img, 0.3))
cv2.imwrite('gaussain.jpg', gaussian_noise(img, 0, 1, 100))

You can see the above methods of adding salt and pepper noise and Gaussian noise to images. For Gaussian noise, the mu parameter in the function gaussian_noise() represents the average of the random number Gaussian distribution, and sigma represents the random number Gaussian. The standard deviation of the distribution, while the parameter delta represents a coefficient indicating the intensity of added Gaussian noise.

Handling noise

OpenCV provides several filtering methods, such as median filtering, bilateral filtering, Gaussian blur, two-dimensional convolution, etc.

import cv2
import random
import numpy as np

# Blur and filter
salt_and_pepper_img = cv2.imread('saltPepper.jpg')
gaussain_img = cv2.imread('gaussain.jpg')

# 2D convolution
kernel = np.ones((5, 5), np.float32) / 25 # Each value is 0.04
conv_2d_img = cv2.filter2D(salt_and_pepper_img, -1, kernel)
cv2.imwrite('filter_2d_img.jpg', conv_2d_img)

# Median filter
median_blur_img = cv2.medianBlur(salt_and_pepper_img, 5) # Parameter 5 represents the area pixel value of size 5x5 for calculation
cv2.imwrite('median_blur_img.jpg', median_blur_img)

# Gaussian blur
gaussian_blur_img = cv2.GaussianBlur(gaussian_img, (5, 5), 0)
cv2.imwrite('gaussian_blur_img.jpg', gaussian_blur_img)

# Bilateral filtering
bilateral_filter_img = cv2.bilateralFilter(gaussain_img, 9, 75, 75) # 9 represents the neighborhood diameter, and the two parameters 75 represent the value range and spatial standard deviation respectively.
cv2.imwrite('bilateral_filter_img.jpg', bilateral_filter_img)

It can be seen that the median filter has the best effect.