Tuần 2: Phép toán với điểm – Điểu chỉnh độ tương phản

Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Ta sẽ nhắc lại các kiến thức đã học ở bài tuần 1:

  • Ảnh số là một hàm với mảng 2 chiều f(x,y)f(x,y)f(x,y)
  • Có nhiều loại ảnh số: chụp dùng cảm ứng ánh sáng, hoặc các loại sóng, hoặc hàm tùy chỉnh
  • Và chúng ta cũng biết cài đặt thư viện: OpenCV, Python, Jupyter Notebook
  • Định nghĩa: số hóa ảnh là biến đổi một ảnh (hay một hàm) liên tục trong không gian cũng như theo giá trị thành dạng số rời rạc.
  • Có 2 bước:
    • Lấy mẫu (sampling): đo giá trị trong các khoảng không gian
    • Lượng tử hóa (quantization): ánh xạ cường độ (hoặc giá trị) đo được thành một số hữu hạn các mức rời rạc Để cho trực quan hơn, ta có thể xem ví dụ dưới đây: 😀

Hình 2.16 a là hình ảnh một đối tượng ảnh liên tục mà ta muốn chuyển đổi sang dạng ảnh số gọi là ảnh gốc.

Hình 2.16 b thể hiện các giá trị độ lớn của ảnh gốc dọc theo đoạn thẳng AB.

Để lấy mẫu hàm này, ta sẽ chiếu đoạn AB lên một máy ảnh, với mỗi vạch là chỗ nhận điểm ảnh, (các bạn cứ coi như 1 tâm pin mặt trời nhận năng lượng mặt trời (nếu cường độ cao sẽ là 1 nếu không có sẽ là 0) như hình 2.16 c. Tập hợp các vị trí rời rạc đó cho ta một hàm đã được lấy mẫu.

Hình bên phải của 2.16 c là cho biết miền giá trị của cường độ chia thành 8 khoảng rời rạc hay còn gọi là số trạng thái điểm ảnh (trong máy tính được biểu diễn được tính ra là bit biểu diễn nên số trạng thái sẽ là bội của 2, ở trong trường hợp này là 8 – tương ứng là 3 bit). Lượng tử hóa bằng các thực hiện làm tròn giá trị cường độ vào 1 trong 8 khoảng rời rạc đó.

Sau khi thực hiện lấy mẫu và lượng tử hóa, ta có kết quả như sau:

Mức độ lượng tử hóa: Số lượng mức xám được yêu cầu trên một bức ảnh số tương ứng với số lượng bits trên mỗi pixel 😃 Ảnh số thường được lượng tử hoá thành 256 mức xám

Nhận biết bước xám (Tonal level perception)

Nếu mức xám dùng 8 bit nó sẽ là dải liên tục. Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Biến đổi gamma

vout=vinγv_{out} = v_{in}^gammavout​=vinγ​

vinv_{in}vin​ : độ sáng thực tế (actual luminance value)

voutv_{out}vout​: độ sáng cảm nhận (output luminance value) Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Ta sẽ có các ví dụ sau:

Cho dải màu xám 16 mức, với gamma = 1 thì nó sẽ giữ nguyên như sau:

Link code : here

# Không điều chỉnh gamma (no adjustment) draw_quantization_img( adjust_gamma(gray_16, gamma=1), height=2 )

Với gamma > 1, ta thấy nếu giá trị đầu vào là tối (thấp) thì đẩu ra là tối hơn, ví dụ đầu vào là giá trị 17 thì đầu ra là giá trị 0:

Link code: here

#with gamma >1, the levels are shifted toward the the darker end of the spectrum draw_quantization_img( adjust_gamma(gray_16, gamma=2.2), height=2 )

Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản Với gamma < 1, các giá trị đầu vào là thấp thì đẩu ra sáng hơn, ví dụ đầu vào là 17 đầu ra là giá trị 74:

Link code: here

#with gamma < 1, lighter draw_quantization_img( adjust_gamma(gray_16, gamma=1/2.2, debug=True), height=2 )

Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Sử dụng gamma để điều chỉnh độ tương phản

1. Độ tương phản thấp (Low exposure)

Ví dụ ảnh vào là một ảnh tối như sau: Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản Thì ta cần chỉnh độ sáng lên thì cần gamma < 1:

def adjust_image_gamma(image, gamma = 1.0): image = np.power(image, gamma) max_val = np.max(image.ravel()) image = image/max_val * 255 image = image.astype(np.uint8) return image

Link: here

Ta thử với 1 số giá trị. Với gamma = 0.45

low_adjusted = adjust_image_gamma(low, 0.45) plt.imshow(low_adjusted[:,:,::-1])

Kết quả sẽ như sau, nhìn trông tốt hơn trước : Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Nếu như gamma quá nhỏ thì sao?

Link code: here

# what if gamma is too low? low_adjusted = adjust_image_gamma(low, 0.1) plt.imshow(low_adjusted[:,:,::-1])

Kết quả thì nó quá sáng: Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Ta thử đo thời gian với hàm adjust_image_gamma:

%timeit low_adjusted = adjust_image_gamma(low, 0.1) # kq: 1 loop, best of 3: 2.51 s per loop

Nó rất tốn thời gian, có cách nào nhanh hơn không ?. Thật ra là có Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản. Nó sẽ như sau:

Link code: here

#faster way to compute #reference: https://www.pyimagesearch.com/2015/10/05/opencv-gamma-correction/ def adjust_image_gamma_lookuptable(image, gamma=1.0): # build a lookup table mapping the pixel values [0, 255] to # their adjusted gamma values table = np.array([((i / 255.0) ** gamma) * 255 for i in np.arange(0, 256)]).astype(“uint8”) # apply gamma correction using the lookup table return cv2.LUT(image, table)

Ý tưởng ở đây là dùng bảng chuyển look-up table (LUT) sử dụng hàm cv2.LUT().

Thời gian chạy với hàm này sẽ là :

%timeit adjust_image_gamma_lookuptable(low, 0.45) #kq: 10 loops, best of 3: 27.6 ms per loop

Tốc độ rất nhanh ( 27.6 ms >> 2.51s)

2. Độ tương phản cao (Overexposure)

Với trường hợp này thì ta cần giảm độ sáng xuống, hay tăng độ tối. Vì vậy, sử dụng gamma > 1:

Cho ảnh đầu vào : Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Ở đây sử dụng gamma = 4.

adjusted_high = adjust_image_gamma_lookuptable(high, 4) plt.imshow(adjusted_high[:,:,::-1])

Kết quả đẩu ra:

Correct using pixel transform

Reference: https://docs.opencv.org/3.4/d3/dc1/tutorial_basic_linear_transform.html

Dùng phép toán nhân và cộng g(x)=αf(x)+βg(x) = alpha f(x) + betag(x)=αf(x)+β

αalphaα và βbetaβ còn được gọi là tham số gain và bias, hoặc tham số để điều chỉnh contrast (độ tương phản) và brightness (độ sáng)

Với ảnh số: g(i,j)=α⋅f(i,j)+βg(i, j) = alpha cdot f(i, j) + betag(i,j)=α⋅f(i,j)+β

Đầu vào vẫn là ảnh Overexposure. Link code: here

def pixel_transform(image, alpha = 1.0, beta = 0): ”’ out[pixel] = alpha * image[pixel] + beta ”’ output = np.zeros(image.shape, image.dtype) h, w, ch = image.shape for y in range(h): for x in range(w): for c in range(ch): output[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255) return output transformed_high = pixel_transform(high, 0.5, 20) plt.imshow(transformed_high[:,:,::-1])

Kết quả đầu ra sẽ là :

Có một cách dùng thư viện của opencv để nhanh hơn:

#anyway, a faster transformed_high = cv2.convertScaleAbs(high, 20, 0.5) plt.imshow(transformed_high[:,:,::-1])

Image negatives

Ta có thể chuyển từ ảnh bên trái sang bên phải ( đổi đen thành trắng và trắng thành đen Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản)

Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

Nghĩ có về khó khăn nhưng thật ra rất đơn giản:

negation = 255 – xray plt.imshow(negation, cmap=’gray’)

Combining images

1. Combination of different exposures for high-dynamic range imaging

Ta có 4 ảnh với 4 độ sáng khác nhau:

Ta sẽ kết hợp tính giá trị trung bình để tạo ra 1 ảnh mới đẹp hơn.

Link code: here

#Averaging to enhance contrast hdr = np.mean(stack, axis=0) hdr = hdr.astype(np.uint8) plt.rcParams[‘figure.figsize’] = [8, 8] plt.imshow(hdr[:,:,::-1])

Kết quả sẽ ra như sau: Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

2. Phép trừ ảnh:

Để tìm ra sự khác biệt giữa 2 ảnh với nhau. Đâu tiên ta sẽ trừ 2 ảnh sau đó tăng độ tương phản để nhìn rõ sự khac nhau hơn: Tuần 2: Phép toán với điểm - Điểu chỉnh độ tương phản

3. Video background subtraction

Từ phép trừ ảnh, ta ứng dụng váo video để tìm sự khác biệt khung hình trước và sau:

Github: here

Colab: Here

Slide: Here

Intensity Transformation Operations on Images

Bài viết đến đây đã dài, nếu có thắc mắc hoặc sai sót gì các bạn có thể comment xuống dưới. Bài Tiếp theo chúng ta tìm hiểu Histogram. Xin chào và hẹn gặp lại các ban.