Ôn lại bài tuần 1
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
- 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
Số hoá ảnh
- Đị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 chia đoạnh AB thành các khoảng bằng nhau như hình 2.16 c. Trong đó các vị trí lấy mẫu được đánh dấu bởi một đoạn thẳng nhỏ ở phía dưới hình và giá trị của mỗi mẫu được thể hiện là hình tròn nhỏ trên hàm. 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 trá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. Lượng tử hóa bằng các thực hiện gaasnmooxi 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
Các biến đổi trên ảnh
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.
Biến đổi gamma
: độ sáng thực tế (actual luminance value)
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
1 2 3 4 5 6 | <span class="token comment"># Không điều chỉnh gamma (no adjustment) </span> draw_quantization_img<span class="token punctuation">(</span> adjust_gamma<span class="token punctuation">(</span>gray_16<span class="token punctuation">,</span> gamma<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> height<span class="token operator">=</span><span class="token number">2</span> <span class="token punctuation">)</span> |
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
1 2 3 4 5 6 | <span class="token comment">#with gamma >1, the levels are shifted toward the the darker end of the spectrum</span> draw_quantization_img<span class="token punctuation">(</span> adjust_gamma<span class="token punctuation">(</span>gray_16<span class="token punctuation">,</span> gamma<span class="token operator">=</span><span class="token number">2.2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> height<span class="token operator">=</span><span class="token number">2</span> <span class="token punctuation">)</span> |
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
1 2 3 4 5 6 | <span class="token comment">#with gamma < 1, lighter</span> draw_quantization_img<span class="token punctuation">(</span> adjust_gamma<span class="token punctuation">(</span>gray_16<span class="token punctuation">,</span> gamma<span class="token operator">=</span><span class="token number">1</span><span class="token operator">/</span><span class="token number">2.2</span><span class="token punctuation">,</span> debug<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">,</span> height<span class="token operator">=</span><span class="token number">2</span> <span class="token punctuation">)</span> |
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:
Thì ta cần chỉnh độ sáng lên thì cần gamma < 1:
1 2 3 4 5 6 7 | <span class="token keyword">def</span> <span class="token function">adjust_image_gamma</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> gamma <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">)</span><span class="token punctuation">:</span> image <span class="token operator">=</span> np<span class="token punctuation">.</span>power<span class="token punctuation">(</span>image<span class="token punctuation">,</span> gamma<span class="token punctuation">)</span> max_val <span class="token operator">=</span> np<span class="token punctuation">.</span><span class="token builtin">max</span><span class="token punctuation">(</span>image<span class="token punctuation">.</span>ravel<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> image <span class="token operator">=</span> image<span class="token operator">/</span>max_val <span class="token operator">*</span> <span class="token number">255</span> image <span class="token operator">=</span> image<span class="token punctuation">.</span>astype<span class="token punctuation">(</span>np<span class="token punctuation">.</span>uint8<span class="token punctuation">)</span> <span class="token keyword">return</span> image |
Link: here
Ta thử với 1 số giá trị. Với gamma = 0.45
1 2 3 | low_adjusted <span class="token operator">=</span> adjust_image_gamma<span class="token punctuation">(</span>low<span class="token punctuation">,</span> <span class="token number">0.45</span><span class="token punctuation">)</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>low_adjusted<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Kết quả sẽ như sau, nhìn trông tốt hơn trước :
Nếu như gamma quá nhỏ thì sao?
Link code: here
1 2 3 4 | <span class="token comment"># what if gamma is too low?</span> low_adjusted <span class="token operator">=</span> adjust_image_gamma<span class="token punctuation">(</span>low<span class="token punctuation">,</span> <span class="token number">0.1</span><span class="token punctuation">)</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>low_adjusted<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Kết quả thì nó quá sáng:
Ta thử đo thời gian với hàm adjust_image_gamma:
1 2 3 | <span class="token operator">%</span>timeit low_adjusted <span class="token operator">=</span> adjust_image_gamma<span class="token punctuation">(</span>low<span class="token punctuation">,</span> <span class="token number">0.1</span><span class="token punctuation">)</span> <span class="token comment"># kq: 1 loop, best of 3: 2.51 s per loop</span> |
Nó rất tốn thời gian, có cách nào nhanh hơn không ?. Thật ra là có . Nó sẽ như sau:
Link code: here
1 2 3 4 5 6 7 8 9 10 11 | <span class="token comment">#faster way to compute</span> <span class="token comment">#reference: https://www.pyimagesearch.com/2015/10/05/opencv-gamma-correction/</span> <span class="token keyword">def</span> <span class="token function">adjust_image_gamma_lookuptable</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> gamma<span class="token operator">=</span><span class="token number">1.0</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># build a lookup table mapping the pixel values [0, 255] to</span> <span class="token comment"># their adjusted gamma values</span> table <span class="token operator">=</span> np<span class="token punctuation">.</span>array<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">/</span> <span class="token number">255.0</span><span class="token punctuation">)</span> <span class="token operator">**</span> gamma<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">255</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> np<span class="token punctuation">.</span>arange<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">256</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span>astype<span class="token punctuation">(</span><span class="token string">"uint8"</span><span class="token punctuation">)</span> <span class="token comment"># apply gamma correction using the lookup table</span> <span class="token keyword">return</span> cv2<span class="token punctuation">.</span>LUT<span class="token punctuation">(</span>image<span class="token punctuation">,</span> table<span class="token punctuation">)</span> |
Ý 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à :
1 2 3 | <span class="token operator">%</span>timeit adjust_image_gamma_lookuptable<span class="token punctuation">(</span>low<span class="token punctuation">,</span> <span class="token number">0.45</span><span class="token punctuation">)</span> <span class="token comment">#kq: 10 loops, best of 3: 27.6 ms per loop</span> |
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 :
Ở đây sử dụng gamma = 4.
1 2 3 | adjusted_high <span class="token operator">=</span> adjust_image_gamma_lookuptable<span class="token punctuation">(</span>high<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>adjusted_high<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
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
và
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ố:
Đầu vào vẫn là ảnh Overexposure.
Link code: here
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">def</span> <span class="token function">pixel_transform</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> alpha <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">,</span> beta <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">''' out[pixel] = alpha * image[pixel] + beta '''</span> output <span class="token operator">=</span> np<span class="token punctuation">.</span>zeros<span class="token punctuation">(</span>image<span class="token punctuation">.</span>shape<span class="token punctuation">,</span> image<span class="token punctuation">.</span>dtype<span class="token punctuation">)</span> h<span class="token punctuation">,</span> w<span class="token punctuation">,</span> ch <span class="token operator">=</span> image<span class="token punctuation">.</span>shape <span class="token keyword">for</span> y <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span>h<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">for</span> x <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span>w<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">for</span> c <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span>ch<span class="token punctuation">)</span><span class="token punctuation">:</span> output<span class="token punctuation">[</span>y<span class="token punctuation">,</span>x<span class="token punctuation">,</span>c<span class="token punctuation">]</span> <span class="token operator">=</span> np<span class="token punctuation">.</span>clip<span class="token punctuation">(</span>alpha<span class="token operator">*</span>image<span class="token punctuation">[</span>y<span class="token punctuation">,</span>x<span class="token punctuation">,</span>c<span class="token punctuation">]</span> <span class="token operator">+</span> beta<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span> <span class="token keyword">return</span> output |
1 2 3 | transformed_high <span class="token operator">=</span> pixel_transform<span class="token punctuation">(</span>high<span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>transformed_high<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Kết quả đầu ra sẽ là :
Có một cách dùng thư viện của opencv để nhanh hơn:
1 2 3 4 | <span class="token comment">#anyway, a faster </span> transformed_high <span class="token operator">=</span> cv2<span class="token punctuation">.</span>convertScaleAbs<span class="token punctuation">(</span>high<span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">)</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>transformed_high<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
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 )
Nghĩ có về khó khăn nhưng thật ra rất đơn giản:
1 2 3 | negation <span class="token operator">=</span> <span class="token number">255</span> <span class="token operator">-</span> xray plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>negation<span class="token punctuation">,</span> cmap<span class="token operator">=</span><span class="token string">'gray'</span><span class="token punctuation">)</span> |
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
1 2 3 4 5 6 | <span class="token comment">#Averaging to enhance contrast</span> hdr <span class="token operator">=</span> np<span class="token punctuation">.</span>mean<span class="token punctuation">(</span>stack<span class="token punctuation">,</span> axis<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span> hdr <span class="token operator">=</span> hdr<span class="token punctuation">.</span>astype<span class="token punctuation">(</span>np<span class="token punctuation">.</span>uint8<span class="token punctuation">)</span> plt<span class="token punctuation">.</span>rcParams<span class="token punctuation">[</span><span class="token string">'figure.figsize'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">]</span> plt<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>hdr<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">,</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Kết quả sẽ ra như sau:
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:
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:
Tài liệu
Github: here
Colab: Here
Slide: Here
Kết luận
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.