Xử lý ảnh - OpenCV đọc ghi hình ảnh (code Python và C++)

  Sep 21, 2018      2m
   

OpenCV - tut 1

Xử lý ảnh - OpenCV đọc ghi hình ảnh (code Python và C++)

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):

Anh girl xinh opencv

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ụ.

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ả:

Anh girl xinh opencv yellow

Ả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.

Sẽ có series các bài tiếp theo về dùng thư viện OpenCV trong xử lý ảnh, các bạn nhớ like trang Facebook để đón xem thông báo bài viết mới nhé! : https://www.facebook.com/minhng.info

Danh sách bài viết series OpenCV: