Các phép biến đổi ảnh cơ bản
Biến đổi xử lý ảnh là tập hợp các kỹ thuật nhằm thay đổi, cải thiện hoặc trích xuất thông tin từ ảnh số phục vụ cho nhận dạng, phân tích và thị giác máy tính. Các phép biến đổi được chia thành ba nhóm chính: biến đổi trên điểm ảnh, biến đổi cục bộ và biến đổi toàn cục.
Biến đổi trên điểm ảnh tác động trực tiếp lên từng pixel độc lập, không xét đến các điểm lân cận. Nhóm này bao gồm các phép điều chỉnh độ sáng, độ tương phản, chuẩn hóa cường độ, biến đổi log, hiệu chỉnh gamma, nhị phân hóa, ảnh âm bản, bảng tra LUT và cân bằng histogram. Các phép này thường dùng để tăng cường ảnh, cải thiện độ tương phản và tiền xử lý dữ liệu.
Biến đổi cục bộ xác định giá trị pixel đầu ra dựa trên pixel trung tâm và các điểm lân cận thông qua các mặt nạ hoặc cửa sổ trượt. Tiêu biểu là phép tích chập, các bộ lọc tuyến tính như lọc trung bình, Gaussian, Laplacian, Sobel, Prewitt, Roberts; các bộ lọc phi tuyến như lọc trung vị; và các phép hình thái học như erosion, dilation, opening và closing. Nhóm này rất quan trọng trong khử nhiễu, làm mượt và phát hiện biên.
Biến đổi toàn cục làm việc trong miền tần số, tiêu biểu là biến đổi Fourier và biến đổi cosin rời rạc (DCT). Các phép này được sử dụng rộng rãi trong lọc tần số, nén ảnh (JPEG), khôi phục và phân tích ảnh nâng cao.
Thay đổi độ sáng, độ tương phản, histogram
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# 1. BIẾN ĐỔI ĐỘ SÁNG
# =========================
c = 50 # tăng sáng (âm thì giảm)
bright = np.clip(img + c, 0, 255).astype(np.uint8)
# =========================
# 2. BIẾN ĐỔI ĐỘ TƯƠNG PHẢN
# =========================
alpha = 1.5 # >1 tăng, <1 giảm
contrast = np.clip(alpha * img, 0, 255).astype(np.uint8)
# =========================
# 3. HISTOGRAM
# =========================
hist_img = cv2.calcHist([img], [0], None, [256], [0,256])
hist_bright = cv2.calcHist([bright], [0], None, [256], [0,256])
hist_contrast = cv2.calcHist([contrast], [0], None, [256], [0,256])
# =========================
# HIỂN THỊ ẢNH
# =========================
plt.figure(figsize=(12,6))
plt.subplot(2,3,1)
plt.imshow(img, cmap='gray')
plt.title("Ảnh gốc")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
plt.subplot(2,3,2)
plt.imshow(bright, cmap='gray')
plt.title("Độ sáng +50")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
plt.subplot(2,3,3)
plt.imshow(contrast, cmap='gray')
plt.title("Tương phản x1.5")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# =========================
# HIỂN THỊ HISTOGRAM
# =========================
plt.subplot(2,3,4)
plt.plot(hist_img, color='black')
plt.title("Histogram ảnh gốc")
plt.xlim([0,255])
plt.subplot(2,3,5)
plt.plot(hist_bright, color='black')
plt.title("Histogram độ sáng")
plt.xlim([0,255])
plt.subplot(2,3,6)
plt.plot(hist_contrast, color='black')
plt.title("Histogram tương phản")
plt.xlim([0,255])
plt.tight_layout()
plt.show()
Kết quả thay đổi độ sáng, histogram, độ tương phản

Biến đổi phi tuyến
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# 1. BIẾN ĐỔI LOG
# g(x,y) = c * log(1 + f(x,y))
# =========================
c = 255 / np.log(1 + img.max())
log_img = c * np.log(1 + img)
log_img = np.uint8(log_img)
# =========================
# 2. HIỆU CHỈNH GAMMA
# g(x,y) = f(x,y)^gamma
# =========================
gamma = 0.5 # <1: sáng, >1: tối
gamma_img = np.power(img / 255.0, gamma) * 255
gamma_img = gamma_img.astype(np.uint8)
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(12,4))
# Ảnh gốc
plt.subplot(1,3,1)
plt.imshow(img, cmap='gray')
plt.title("Ảnh gốc")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Log transform
plt.subplot(1,3,2)
plt.imshow(log_img, cmap='gray')
plt.title("Biến đổi Log")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Gamma correction
plt.subplot(1,3,3)
plt.imshow(gamma_img, cmap='gray')
plt.title("Hiệu chỉnh Gamma (γ=0.5)")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
plt.tight_layout()
plt.show()
Kết quả biến đổi phi tuyến

Biến đổi nhị phân
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# 1. NHỊ PHÂN HÓA NGƯỠNG CỐ ĐỊNH
# g(x,y) = 255 nếu f(x,y) >= T, ngược lại = 0
# =========================
T = 128
_, binary_fixed = cv2.threshold(img, T, 255, cv2.THRESH_BINARY)
# =========================
# 2. NHỊ PHÂN HÓA NGƯỠNG THÍCH NGHI
# =========================
binary_adaptive = cv2.adaptiveThreshold(
img,
255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,
11, # kích thước cửa sổ
2 # hằng số trừ
)
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(12,4))
# Ảnh gốc
plt.subplot(1,3,1)
plt.imshow(img, cmap='gray')
plt.title("Ảnh gốc")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Nhị phân hóa ngưỡng cố định
plt.subplot(1,3,2)
plt.imshow(binary_fixed, cmap='gray')
plt.title("Nhị phân hóa (T = 128)")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Nhị phân hóa thích nghi
plt.subplot(1,3,3)
plt.imshow(binary_adaptive, cmap='gray')
plt.title("Nhị phân hóa thích nghi")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
plt.tight_layout()
plt.show()
Kết quả biến đổi nhị phân

Tạo phim âm bản
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
#img = cv2.imread("input2.jpg", cv2.IMREAD_GRAYSCALE)
img = cv2.imread("input2.jpg", cv2.IMREAD_ANYCOLOR)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# ẢNH ÂM BẢN
# g(x,y) = 255 - f(x,y)
# =========================
negative = 255 - img
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(8,4))
# Ảnh gốc
plt.subplot(1,2,1)
plt.imshow(img, cmap='gray')
plt.title("Ảnh gốc")
plt.axis('off')
plt.text(
5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6)
)
# Ảnh âm bản
plt.subplot(1,2,2)
plt.imshow(negative, cmap='gray')
plt.title("Ảnh âm bản")
plt.axis('off')
plt.text(
5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6)
)
plt.tight_layout()
plt.show()
Kết quả tạo phim âm bản

Code cân bằng histogram
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# CÂN BẰNG HISTOGRAM
# =========================
equal = cv2.equalizeHist(img)
# =========================
# TÍNH HISTOGRAM
# =========================
hist_img = cv2.calcHist([img], [0], None, [256], [0,256])
hist_equal = cv2.calcHist([equal], [0], None, [256], [0,256])
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(12,6))
# Ảnh gốc
plt.subplot(2,2,1)
plt.imshow(img, cmap='gray')
plt.title("Ảnh gốc")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Ảnh sau cân bằng histogram
plt.subplot(2,2,2)
plt.imshow(equal, cmap='gray')
plt.title("Ảnh sau cân bằng histogram")
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6))
# Histogram ảnh gốc
plt.subplot(2,2,3)
plt.plot(hist_img, color='black')
plt.title("Histogram ảnh gốc")
plt.xlim([0,255])
# Histogram sau cân bằng
plt.subplot(2,2,4)
plt.plot(hist_equal, color='black')
plt.title("Histogram sau cân bằng")
plt.xlim([0,255])
plt.tight_layout()
plt.show()
Kết quả cân bằng histogram

Code lọc tích chập
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# KERNELS
# =========================
kernel_mean = np.ones((3,3), np.float32) / 9
kernel_gaussian = np.array([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]], np.float32) / 16
sobel_x = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]], np.float32)
sobel_y = np.array([[-1, -2, -1],
[ 0, 0, 0],
[ 1, 2, 1]], np.float32)
prewitt_x = np.array([[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]], np.float32)
prewitt_y = np.array([[-1, -1, -1],
[ 0, 0, 0],
[ 1, 1, 1]], np.float32)
laplace = np.array([[0, -1, 0],
[-1, 4, -1],
[0, -1, 0]], np.float32)
roberts_x = np.array([[1, 0],
[0, -1]], np.float32)
roberts_y = np.array([[0, 1],
[-1, 0]], np.float32)
# =========================
# TÍCH CHẬP
# =========================
mean_img = cv2.filter2D(img, -1, kernel_mean)
gaussian_img = cv2.filter2D(img, -1, kernel_gaussian)
sobelx = cv2.filter2D(img, cv2.CV_64F, sobel_x)
sobely = cv2.filter2D(img, cv2.CV_64F, sobel_y)
sobel = cv2.magnitude(sobelx, sobely)
sobel = np.uint8(np.clip(sobel, 0, 255))
prewittx = cv2.filter2D(img, cv2.CV_64F, prewitt_x)
prewitty = cv2.filter2D(img, cv2.CV_64F, prewitt_y)
prewitt = cv2.magnitude(prewittx, prewitty)
prewitt = np.uint8(np.clip(prewitt, 0, 255))
laplace_img = cv2.filter2D(img, cv2.CV_64F, laplace)
laplace_img = np.uint8(np.clip(np.abs(laplace_img), 0, 255))
robertsx = cv2.filter2D(img, cv2.CV_64F, roberts_x)
robertsy = cv2.filter2D(img, cv2.CV_64F, roberts_y)
roberts = cv2.magnitude(robertsx, robertsy)
roberts = np.uint8(np.clip(roberts, 0, 255))
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(15,10))
images = [
(img, "Ảnh gốc"),
(mean_img, "Mean filter"),
(gaussian_img, "Gaussian filter"),
(sobel, "Sobel"),
(prewitt, "Prewitt"),
(laplace_img, "Laplace"),
(roberts, "Roberts")
]
for i, (image, title) in enumerate(images):
plt.subplot(3,3,i+1)
plt.imshow(image, cmap='gray')
plt.title(title)
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=8,
bbox=dict(facecolor='black', alpha=0.6))
plt.tight_layout()
plt.show()
Kết quả lọc tích chập

Code lọc thông thấp, lọc thông cao, lọc hình thái học
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Đọc ảnh xám
img = cv2.imread("input.jpg", cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError("Không tìm thấy input.jpg")
# =========================
# 1. LỌC THÔNG THẤP
# =========================
mean = cv2.blur(img, (3,3))
gaussian = cv2.GaussianBlur(img, (3,3), 0)
# =========================
# 2. LỌC THÔNG CAO
# =========================
kernel_highpass = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]])
highpass = cv2.filter2D(img, -1, kernel_highpass)
laplace = cv2.Laplacian(img, cv2.CV_64F)
laplace = np.uint8(np.clip(np.abs(laplace), 0, 255))
# =========================
# 3. LỌC ĐẠO HÀM
# =========================
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobel = cv2.magnitude(sobelx, sobely)
sobel = np.uint8(np.clip(sobel, 0, 255))
prewittx = cv2.filter2D(img, cv2.CV_64F,
np.array([[-1,0,1],
[-1,0,1],
[-1,0,1]]))
prewitty = cv2.filter2D(img, cv2.CV_64F,
np.array([[-1,-1,-1],
[0,0,0],
[1,1,1]]))
prewitt = cv2.magnitude(prewittx, prewitty)
prewitt = np.uint8(np.clip(prewitt, 0, 255))
# =========================
# 4. LỌC HÌNH THÁI HỌC
# =========================
kernel = np.ones((3,3), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
dilation = cv2.dilate(img, kernel, iterations=1)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# =========================
# HIỂN THỊ KẾT QUẢ
# =========================
plt.figure(figsize=(15,12))
results = [
(img, "Ảnh gốc"),
(mean, "Low-pass: Mean"),
(gaussian, "Low-pass: Gaussian"),
(highpass, "High-pass filter"),
(laplace, "High-pass: Laplace"),
(sobel, "Derivative: Sobel"),
(prewitt, "Derivative: Prewitt"),
(erosion, "Morphology: Erosion"),
(dilation, "Morphology: Dilation"),
(opening, "Morphology: Opening"),
(closing, "Morphology: Closing")
]
for i, (image, title) in enumerate(results):
plt.subplot(4,3,i+1)
plt.imshow(image, cmap='gray')
plt.title(title)
plt.axis('off')
plt.text(5, 15, "Nguyễn Văn Chuân",
color='white', fontsize=8,
bbox=dict(facecolor='black', alpha=0.6))
plt.tight_layout()
plt.show()
Kết quả lọc thông thấp, lọc thông cao, lọc hình thái học

https://tritue.edu.vn/tuecode/tracnghiem30/site/data/YVdRc01qUTNMRjl5YjNWMFpTeGlZV2wyYVdWMEwzQnZjM1F2ZG1sbGR3PT0%3D