<p>我在opencv的帮助下想出了一个非常简单的解决方案。在</p>
<ol>
<li><p>调整图像大小,以便通过轮廓删除异常值(更容易测量区域)</p>
<pre><code>std::string const img_name = "cow_00";
Mat input = imread("../forum_quest/data/" + img_name + ".jpg");
cout<<input.size()<<endl;
if(input.empty()){
cerr<<"cannot open image\n";
return;
}
if(input.cols > 1000){
cv::resize(input, input, {1000, (int)(1000.0/input.cols * input.rows)}, 0.25, 0.25);
}
</code></pre></li>
<li><p>在1/3的顶部裁剪区域</p>
<pre><code>//Assume the text always lie on top 1/3 of the image
Mat crop_region;
input(Rect(0, 0, input.cols, input.rows/3)).copyTo(crop_region);
</code></pre></li>
<li><p>提取前景</p>
^{3美元</li>
</ol>
<p><a href="https://i.stack.imgur.com/xDtUU.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xDtUU.jpg" alt="enter image description here"/></a></p>
<p><a href="https://i.stack.imgur.com/KkSH7.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/KkSH7.jpg" alt="enter image description here"/></a></p>
<p><a href="https://i.stack.imgur.com/PUE7G.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/PUE7G.jpg" alt="enter image description here"/></a></p>
<ol start=“4”>
<li><p>提取轮廓,如果轮廓精度较低,可以使用ERFilter提取文本</p>
<pre><code>std::vector<std::vector<cv::Point>> get_text_contours(cv::Mat const &input)
{
//Find the contours of candidate text, remove outlier with
//some contour properties
//Try ERFilter of opencv if accuracy of this solution is low
vector<cpoints> contours;
findContours(input, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
auto outlier = [](cpoints const &cp)
{
auto const rect = cv::boundingRect(cp);
return rect.width > rect.height && (rect.area() < 900 || rect.area() >= 10000);
};
auto it = std::remove_if(std::begin(contours), std::end(contours), outlier);
contours.erase(it, std::end(contours));
std::sort(std::begin(contours), std::end(contours), [](cpoints const &lhs, cpoints const &rhs)
{
return cv::boundingRect(lhs).x < cv::boundingRect(rhs).x;
});
return contours;
}
</code></pre></li>
<li><p>创建字符分类器并在文本候选中循环</p>
<pre><code> string const vocabulary = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // must have the same order as the classifier output classes
Ptr<text::OCRHMMDecoder::ClassifierCallback> ocr = text::loadOCRHMMClassifierCNN("OCRBeamSearch_CNN_model_data.xml.gz");
vector<int> out_classes;
vector<double> out_confidences;
for(size_t i = 0; i < text_contours.size(); ++i){
Scalar const color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours(text_mask, text_contours, static_cast<int>(i), color, 2);
auto const text_loc = boundingRect(text_contours[i]);
//crop_region can gain highest accuracy since it is trained on scene image
rectangle(crop_region, text_loc, color, 2);
ocr->eval(crop_region(text_loc), out_classes, out_confidences);
cout << "OCR output = \"" << vocabulary[out_classes[0]]
<< "\" with confidence "
<< out_confidences[0] << std::endl;
putText(crop_region, string(1, vocabulary[out_classes[0]]), Point(text_loc.x, text_loc.y - 5),
FONT_HERSHEY_SIMPLEX, 2, Scalar(255, 0, 0), 2);
imshow("text_mask", text_mask);
imshow("crop_region", crop_region(text_loc));
waitKey();
}
</code></pre></li>
</ol>
<p>结果:</p>
<p><a href="https://i.stack.imgur.com/lJkcP.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lJkcP.jpg" alt="enter image description here"/></a>
<a href="https://i.stack.imgur.com/bq2Th.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/bq2Th.jpg" alt="enter image description here"/></a>
<a href="https://i.stack.imgur.com/7s2m3.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/7s2m3.jpg" alt="enter image description here"/></a></p>
<p>完整的源代码放在<a href="https://github.com/stereomatchingkiss/blogCodes2/blob/master/forum_quest/extract_cow_number.cpp" rel="nofollow noreferrer">github</a></p>