Với các loại text có format cố định thì việc đọc rất dễ dàng. Tọa độ đã được xác định, chỉ cần chỉ định vùng text cố định là được. Còn các loại văn bản khác thì cần xác định vị trí trước sau đó mới nhận dạng ký tự.
Việc này giúp cho đọc text nhanh hơn là tìm toàn bộ ảnh. Tuy nhiên có thể bị miss (bỏ sót) vùng text nên các bạn cần cân nhắc kỹ.
Ví dụ như thẻ cào điện thoại, vị trí đã có sẵn cố định:
Nhưng với các loại văn bản khác thì text không cố định, do đó cần xử lý thêm. Phương pháp trong bài này là sử dụng lọc Sobel kết hợp hình thái học (morphology). Độ chính xác tương đối & cũng không thể áp dụng cho mọi loại văn bản. Do đó các tham số sử dụng cần được điều chỉnh cho các nhóm văn bản khác nhau.
Thuật toán
Sử dụng ảnh bên dưới để demo thuật toán tìm text trong văn bản
Đầu tiên dùng lọc Sobel
Sau đó phân ngưỡng (threshold)
Dùng phép biến đổi hình thái học CLOSE để fill các lỗ trống
Sau đó tìm contour rồi vẽ kết quả
Một vài lưu ý
– Do lọc Sobel dx bị lệch phải (dx = 1) nên phải move các hình chữ nhật qua trái 1 chút
– Các tham số của hình thái học, lọc Sobel phải là số lẻ (1,3,5,7,…)
– Tùy theo loại văn bản, kích cỡ chữ mà tìm tham số hình thái học phù hợp
– Trong hình trên vẫn có sai sót nhỏ ở góc dưới bên trái ảnh
– Bên dưới là minh họa phép biến đổi CLOSE
Code C++
Hàm này có chức năng tìm các vùng hình chữ nhật chứa text trong ảnh
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 |
std::vector<cv::Rect> DetectTextLocation(cv::Mat img) { std::vector<cv::Rect> boundRects; cv::Mat matGray, matSobel, matThreshold, matElement; cv::cvtColor(img, matGray, CV_BGR2GRAY); cv::Sobel(matGray, matSobel, CV_8U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT); cv::imshow("matSobel", matSobel); cv::threshold(matSobel, matThreshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); cv::imshow("matThreshold", matThreshold); matElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(19, 3)); cv::morphologyEx(matThreshold, matThreshold, CV_MOP_CLOSE, matElement); //Does the trick cv::imshow("CLOSE", matThreshold); std::vector< std::vector< cv::Point> > contours; cv::findContours(matThreshold, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); std::vector<std::vector<cv::Point> > contours_poly(contours.size()); for (int i = 0; i < contours.size(); i++) { if (contours[i].size() > 100) { cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true); cv::Rect appRect(cv::boundingRect(cv::Mat(contours_poly[i]))); if (appRect.width > appRect.height) { appRect.x -= img.cols / 100; appRect.width += img.cols / 100; boundRects.push_back(appRect); } } } return boundRects; } |
anh có thể cho em xin code của cả bài này được ko ạ
Bạn lấy project config sẵn rồi bỏ code vào là chạy được nhé: https://thigiacmaytinh.com/setup-project-opencv-bang-c/
Anh oi. Em mới học môn này. Mà em chỉ biết sài Python thôi ạ. :((
Ok, mình sẽ cố gắng cập nhật code python
kể có code python phần này thì tốt quá 🙁 , em đọc code C ++ hơi lú
Tìm tên hàm rồi thay line by line thôi bạn