Xử lý ảnh - OpenCV đọc ghi hình ảnh (code Python và C++)
OpenCV - tut 1
Môi trường
- Linux (bài viết sử dụng Ubuntu 16.04)
- OpenCV (bài viết sử dụng OpenCV 3.4.1)
- Python (bài viết sử dụng Python 3.5.5)
Đọc ảnh với OpenCV - Python
Hình mẫu để đọc lên bằng OpenCV (keyword tìm kiếm cho ông nào cần ^^: girl xinh):
Bạn có thể download ảnh mẫu về.
File hình ảnh và source code python ở cùng thư mục:
- girl_xinh.jpg
- read.py
read.py: mở đọc file ảnh bằng OpenCV với đoạn code sau:
import cv2
# read image
img = cv2.imread('girl_xinh.jpg')
# image dimension
print('img.shape:', img.shape)
Thực thi lệnh trên terminal để đọc ảnh:
$ python read.py
img.shape: (720, 960, 3)
Cấu trúc tổ chức ảnh được đọc lên bởi OpenCV như sau:
- Ảnh màu OpenCV tổ chức dữ liệu theo: Height, Width, Channel (gọi tắt HWC).
- Ảnh màu OpenCV sắp xếp 3 kênh theo: Blue, Green, Red (BGR). Lưu ý rằng các thư viện ảnh khác có thể tổ chức theo RGB do đó nếu dùng thư viện khác hiển thị ảnh đọc bởi OpenCV sẽ thấy màu sắc bị sai khác với ảnh gốc.
- Ảnh xám OpenCV đọc lên sẽ chỉ có 2 chiều, trường hợp ảnh màu là 3 chiều như ví dụ.
Tham khảo thêm bài viết: Tut 1.1: Xử lý ảnh - Cấu trúc dữ liệu ảnh trong OpenCV. Pixel là gì?
Ghi ảnh với OpenCV - Python
write.py: đọc ảnh, tắt kênh màu xanh dương của ảnh (set về zero)
import cv2
# read image
img = cv2.imread('girl_xinh.jpg')
# replace blue channel with zero
img[:,:,0] = 0
# write / save modified image
cv2.imwrite('girl_xinh_yellow.jpg', img)
Thực thi:
$ python write.py
Mở file girl_xinh_yellow.jpg để xem thành quả:
Ảnh lưu xuống bởi OpenCV trông khá vàng vì bạn vừa tắt kênh màu xanh dương đi bằng cách thiết lập tất cả các giá trị pixel về 0. Do đó màu hình ảnh bị phối màu bởi kênh màu xanh lá và đỏ, mà xanh lá + đỏ = vàng.
Đọc ảnh với OpenCV - C++
OpenCV imread docs: https://docs.opencv.org/3.4.0/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56
read.cpp: mã nguồn đọc file ảnh OpenCV với C++
#include <iostream>
using namespace std;
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
// using namespace cv;
int main() {
cv::Mat img = cv::imread("girl_xinh.jpg");
cout << "img.shape " << img.size << endl;
}
run_read.sh: biên dịch và chạy chương trình
INCLUDE=`pkg-config --cflags opencv`
LIBS=`pkg-config --libs opencv`
g++ ${INCLUDE} read.cpp ${LIBS} -o read -std=c++11 && ./read && rm read
Output:
$ sh run_read.sh
img.shape 720 x 960
Ghi ảnh với OpenCV - C++
write.cpp
#include <iostream>
using namespace std;
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
// using namespace cv;
int main() {
cv::Mat img = cv::imread("girl_xinh.jpg", cv::IMREAD_COLOR);
cout << "img.step " << img.step << endl;
cout << "img.channels() " << img.channels() << endl;
for(int row=0; row<img.rows; row++) {
for(int col=0; col<img.cols; col++) {
*(img.ptr(row, col)) = 0;
}
}
cv::imwrite("girl_xinh_yellow.jpg", img);
}
run_write.sh: build và chạy chương trình C++
INCLUDE=`pkg-config --cflags opencv`
LIBS=`pkg-config --libs opencv`
g++ ${INCLUDE} write.cpp ${LIBS} -o write -std=c++11 && ./write && rm write
Thực thi:
$ sh run_write.sh
Chương trình C++ ghi ảnh kết quả ra file girl_xinh_yellow.jpg cho cùng kết quả với file Python.
Nếu bạn muốn tắt kênh blue + red (tức chỉ giữ lại mỗi kênh green) trong C++ thì bạn thay dòng lệnh:
*(img.ptr(row, col)) = 0;
bằng 3 dòng lệnh sau:
uchar *ptr = img.ptr(row, col);
*ptr = 0;
*(ptr+2) = 0;
Giải thích:
- Tài liệu về hàm ptr(): https://docs.opencv.org/3.4.0/…
- Tổ chức dữ liệu ảnh xám trong OpenCV: [0-255]…[0-255] (dòng 0) -> [0-255]…[0-255] (dòng 1) -> … (dòng theo dòng)
- Tổ chức dữ liệu ảnh màu trong OpenCV: [B][G][R]…[B][G][R] (dòng 0) -> [B][G][R]…[B][G][R] (dòng 1) -> … (dòng theo dòng nhưng giá trị 3 kênh màu liên tiếp nhau rồi mới đến pixel kế tiếp)
- Bởi cách tổ chức dữ liệu đặc thù như trên nên trong ví dụ ta phải lấy pixel [row, col, 0] công thêm 2 để được vị trí màu đỏ tại tọa độ [row, col] và set về zero.
Bài viết tiếp theo: Tut 1.1: Xử lý ảnh - Cấu trúc dữ liệu ảnh trong OpenCV. Pixel là gì?
Cảm ơn bạn đã theo dõi bài viết. Hãy kết nối với tớ nhé!
- Minh: https://www.facebook.com/minhng.info
- Khám phá xử lý ảnh - GVGroup: https://www.facebook.com/groups/ip.gvgroup
Khám phá xử lý ảnh - GVGroup
Danh sách bài viết series OpenCV:
- Hashtag #OpenCV
- Tut 1: Xử lý ảnh - OpenCV đọc ghi hình ảnh (code Python và C++)
- Tut 1.1: Xử lý ảnh - Cấu trúc dữ liệu ảnh trong OpenCV. Pixel là gì?
- Tut 1.2: Xử lý ảnh - Chuyển đổi ảnh OpenCV sang Pillow và ngược lại
- Tut 2: Xử lý ảnh - OpenCV resize, crop và padding hình ảnh (code Python và C++)
- Tut 3: Xử lý ảnh - OpenCV biến đổi mức sáng hình ảnh (code Python)
- Tut 4: Xử lý ảnh - OpenCV vùng quan tâm (ROI) là gì? (code Python)
- Tut 4.1: Xử lý ảnh - OpenCV: vẽ văn bản, đường thẳng, mũi tên, hình chữ nhật, hình tròn, ellipse, đa giác
- Tut 4.2: Xử lý ảnh - Pha trộn ảnh trong OpenCV (blending)
- Tut 5: Xử lý ảnh - OpenCV ảnh nhị phân
- Tut 6: Xử lý ảnh - OpenCV cân bằng sáng (histogram equalization)
- Tut 7: Xử lý ảnh - OpenCV kỹ thuật cửa sổ trượt (sliding window)
- Tut 8: Xử lý ảnh - Convolution là gì?
- Tut 9: Xử lý ảnh - Làm mờ ảnh (blur)
- Tut 10: Xử lý ảnh - Gradient của ảnh là gì?
- Tut 11: Xử lý ảnh - Phát hiện cạnh Canny (Canny Edge Detection)
- Tut 12: Xử lý ảnh - Phát hiện đường thẳng bằng Hough Transform (Hough Line)
- Tut 13: Xử lý ảnh - Hiện thực phát hiện đoạn thẳng dùng Hough Transform (Hough Line)
- Tut 14: Xử lý ảnh - Giải thuật phân vùng Region Growing trên ảnh màu
- Tut 15: Xử lý ảnh - Giải thuật Background Subtraction trên ảnh màu
- Tut 16: Xử lý ảnh - Frame Subtraction để phát hiện chuyển động trong video
- Tut 17: Xử lý ảnh - HOG - Histograms of Oriented Gradients
- Tut 18: Xử lý ảnh - HOG - Huấn luyện mô hình phân loại người
- Tut 19: Xử lý ảnh - HOG - Phát hiện người
- Tut 20: Xử lý ảnh - Tổng hợp kinh nghiệm xử lý ảnh (End)
- Tut 21: Xử lý ảnh - Hiện thực trích đặc trưng Local Binary Patterns (LBP)
- Tut 22: Xử lý ảnh - Trích đặc trưng Gabor filters