Giải thuật xử lý ảnh mosaic
Nốt hôm nay là được nghỉ hẳn một tuần (honho) Trong lúc đang đợi spec của KH mình xin giới thiệu về giải thuật sinh ảnh mosaic từ một ảnh gốc. Không hiểu sinh ảnh mosiac nhằm mục đích gì, chắc chỉ để sinh chơi. (haha) Mosaic có nguồn gốc từ thời Hy Lạp cổ đại với ý nghĩa nguyên thủy là ...
Nốt hôm nay là được nghỉ hẳn một tuần (honho)
Trong lúc đang đợi spec của KH mình xin giới thiệu về giải thuật sinh ảnh mosaic từ một ảnh gốc. Không hiểu sinh ảnh mosiac nhằm mục đích gì, chắc chỉ để sinh chơi. (haha)
- Mosaic có nguồn gốc từ thời Hy Lạp cổ đại với ý nghĩa nguyên thủy là “loại nghệ thuật xứng đáng với trí tưởng tượng bay bổng và lòng kiên trì vô biên”, thuộc loại nghệ thuật có tuổi đời lâu nhất của loài người. (hucau)
Note: Hiệu ứng này có thể được thực hiện bằng Photoshop một cách dễ dàng hơn là ngồi code (yaoming). Ảnh sinh trong bài viết này gọi là ảnh chấm chấm theo phong cách mosaic thì chuẩn hơn (facepalm2)
1. Ý tưởng
Chúng ta sẽ tạo ra một layer gồm các hình tròn trắng trên background màu đen, sau đó thực hiện phép multiplying với layer mosaic tính toán được (really?)
Steps
- Load ảnh gốc đầu vào.
- Áp dụng hiệu ứng pixelate (lấy màu trung bình) của NxN block lân cận cho toàn ảnh.
- Tạo ảnh mặt nạ là các hình tròn trắng (bit 1) và background đen (bit 0).
- Thực hiện phép toán Multiply ảnh màu trung bình với ảnh mặt nạ.
Các bước tạo ảnh có thể hình dung đơn giản như sau:
_Chi tiết hơn ta thử áp dụng vào ảnh 150x150px. Trong trường hợp NxN block, N = 75; _
2. Thực hành
Mình sử dụng C++ và thư viện OpenCV để thực hiện ý tưởng trên.
Mat function colorDot(Mat image) { Mat buffer; // Copy từ ảnh gốc sang ảnh đệm image.copyTo(buffer); Mat dst = Mat::zeros(image.size(), CV_8UC3); Mat cir = Mat::zeros(image.size(), CV_8UC1); // Áp dụng phương thức pixelate cho NxN block lân cận có size = 10x10 int N = 10; for (int i = 0; i < image.rows; i += N) { for (int j = 0; j < image.cols; j += N) { Rect rect = Rect(j, i, N, N) & Rect(0, 0, image.cols, image.rows); // Create block có màu trung bình Mat sub_dst(dst, rect); sub_dst.setTo(mean(image(rect))); // Tạo các hình tròn màu trắng (bit 1) trên layer đen (bit 0), bán kính N/2 circle( cir, Point(j + N/2, i + N/2), N/2-1, CV_RGB(255,255,255), -1, CV_AA ); } } // Convert ảnh circles sang floating-point Mat cir_32f; cir.convertTo(cir_32f, CV_32F); normalize(cir_32f, cir_32f, 0, 1, NORM_MINMAX); // Convert ảnh pixelate sang floating-point Mat dst_32f; dst.convertTo(dst_32f, CV_32F); // Tiến hành phép toán Multiply trên từng channel màu vector<Mat> channels; split(dst_32f, channels); for (int i = 0; i < channels.size(); ++i) { channels[i] = channels[i].mul(cir_32f); } // Merge 3 channels màu lại thành ảnh mosaic merge(channels, dst_32f); dst_32f.convertTo(dst, CV_8U); return dst; }
3. Kết quả
Bên dưới đây là các ảnh đầu vào và đầu ra tương ứng (yeah)
Xử lý realtime với video thu được webcam: