Bản chất của video trong Thị giác máy tính là chuỗi các hình ảnh liên tiếp nhau để tạo ra chuyển động mượt mà. Để mắt người cảm thấy hình ảnh không bị giật thì tối thiểu là 24 fps (frame per second). Do đó, từ video ta có thể tách ra các hình ảnh rồi ghép lại để tạo thành ảnh thumbnail.
Bài này mục đích giới thiệu về các hàm cơ bản của OpenCV cho các bạn mới làm quen. Sau khi làm xong bài này có thể hiểu được:
– Trích xuất frame từ video
– ROI (region of interest)
– Save ảnh
Để tạo ra thumbnail có thể sử dụng Media Player Classic . Mở 1 file video, sau đó chọn menu: File -> Save thumbnails… rồi chọn số dòng, số cột là được ảnh thumbnail. Bên dưới là thumbnail 4×4:
Các bước thực thi của chương trình
– Nhận tham số là: file video, số dòng, số cột, width, height mong muốn
– Tạo 1 ma trận (cv::Mat) output
– Tính toán số frame cần trích xuất = số dòng x số cột
– Trích xuất frame theo thời gian tương ứng
– Với mỗi frame, resize cho phù hợp rồi ghép vào ảnh output
– Save ảnh output
Ví dụ: yêu cầu tạo thumbnail 2 dòng x 2 cột, kích thước output là 640 x 480 pixel với video độ dài 2 phút 30fps:
– Video này có số lượng frame: 2 phút x 60 giây x 30 frame = 3600 frame
– Lấy 4 frame tại vị trí: 0, 1199, 2399 và 3599
– Resize 4 frame thành 320 x 240 pixel
– Ghép lại thành ảnh output theo thứ tự từ trái qua phải, trên xuống dưới
– Save ảnh là hoàn tất
Bên dưới là ảnh ví dụ về ROI: ghép ảnh vào 1 vùng nhỏ của bức ảnh khác
Kết quả sau khi ghép
Source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
#include <iostream> #include <opencv2/opencv.hpp> //khai báo các tham số cần thiết std::string videoPath = "sample.mp4"; int numCol = 2; int numRow = 2; int width = 640; int height = 480; cv::VideoCapture videoCapture; //dùng để trích xuất frame từ video cv::Mat GetFrame(int index) { videoCapture.set(CV_CAP_PROP_POS_FRAMES, index); cv::Mat frame; videoCapture.read(frame); return frame; } void main(int argc, char** argv) { //load video videoCapture = cv::VideoCapture(videoPath); if (!videoCapture.isOpened()) { std::cout<< "Can not load video " << videoPath.c_str(); return; } int totalVideoFrame = videoCapture.get(CV_CAP_PROP_FRAME_COUNT); int numFrame = numCol * numRow; int roiWidth = width / numCol; int roiHeight = height / numRow; cv::Mat matRoi = GetFrame(0); cv::resize(matRoi, matRoi, cv::Size(roiWidth, roiHeight)); cv::Rect roi = cv::Rect(0, 0, roiWidth, roiHeight); //tạo ảnh thumbnail kết quả rỗng cv::Mat matThumbnail = cv::Mat::ones(cv::Size(width, height), CV_8UC3); //copy ảnh tại frame đầu tiên vào ảnh thumbnail matRoi.copyTo(matThumbnail(roi)); int numPart = numFrame - 1; int numFrameAtPart = totalVideoFrame / numPart; int i = 0; for(int r = 0; r<numRow; r++) { for (int c = 0; c < numCol; c++) { int frameIdx = i * numFrameAtPart - 1; if (frameIdx < 0) frameIdx == 0; matRoi = GetFrame(frameIdx); roi = cv::Rect(roiWidth * c, roiHeight * r, roiWidth, roiHeight); cv::resize(matRoi, matRoi, cv::Size(roiWidth, roiHeight)); matRoi.copyTo(matThumbnail(roi)); i++; } } //hiển thị và save ảnh cv::imshow("thumbnail", matThumbnail); cv::imwrite("thumbnail.jpg", matThumbnail); //giải phóng bộ nhớ videoCapture.release(); cv::waitKey(); getchar(); } |
Download full project
Lưu ý: các bạn khi pull code về phải pull cả submodule vì thư viện opencv nằm ở submodule