gpt4 book ai didi

image - 从图像中分割字符

转载 作者:太空宇宙 更新时间:2023-11-03 20:47:43 25 4
gpt4 key购买 nike

我在分割后续车牌图像时遇到问题,同时对后续图像进行阈值处理,字符被分成超过 1 个字符。所以我得到了错误的 OCR 结果。我在对图像进行阈值处理后应用了形态闭合操作,即使在那之后我也无法正确分割字符..

License Plate image 1

License Plate image 2

License Plate image 3

License Plate image 4

上面的图片分割代码如下

#include <iostream>
#include<cv.h>
#include<highgui.h>

using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
IplImage *img1 = cvLoadImage(argv[1] , 0);
IplImage *img2 = cvCloneImage(img1);

cvNamedWindow("Orig");
cvShowImage("Orig",img1);
cvWaitKey(0);

int wind = img1->height;
if (wind % 2 == 0) wind += 1;

cvAdaptiveThreshold(img1, img1, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C,
CV_THRESH_BINARY_INV, wind);

IplImage* temp = cvCloneImage(img1);

cvNamedWindow("Thre");
cvShowImage("Thre",img1);
cvWaitKey(0);

IplConvKernel* kernal = cvCreateStructuringElementEx(3, 3, 1, 1,
CV_SHAPE_RECT,NULL);

cvMorphologyEx(img1, img1, temp, kernal, CV_MOP_CLOSE, 1);

cvNamedWindow("close");
cvShowImage("close",img1);

cvWaitKey(0);
}

下面给出的输出图像..

U Y and 2 are not segmented properly

U, P, Y and 2 are not segmented Properly

U 3 Y 2 and 5 are not segmented properly

谁能提供一种从这些图像中分割字符的好方法...??

最佳答案

我想展示一种快速而肮脏的方法来隔离盘子中的字母/数字,因为字符的实际分割不是问题。当这些是输入图像时:

enter image description here enter image description here enter image description here enter image description here

这是你在我的算法结束时得到的:

enter image description here enter image description here enter image description here enter image description here

因此,我在此答案中讨论的内容将为您提供一些想法,并帮助您摆脱当前分割过程结束时出现的伪影。请记住,这种方法应该只适用于这些类型的图像,如果您需要更强大的东西,您需要调整一些东西或想出全新的方法来做这些事情。

  • 鉴于亮度变化剧烈,最好执行histogram equalization提高对比度并使它们彼此更相似,以便所有其他技术和参数与它们一起工作:

enter image description here enter image description here enter image description here enter image description here

  • 接下来,一个 bilateral filter可用于平滑图像,同时保留对象的边缘,这对于二值化过程很重要。这个过滤器需要更多的处理能力than others .

enter image description here enter image description here enter image description here enter image description here

enter image description here enter image description here enter image description here enter image description here

  • 二值化的结果和你的很相似,所以我想出了一个使用findContours()的方法。删除较小和较大的部分:

enter image description here enter image description here enter image description here enter image description here

  • 结果似乎好一点,但它破坏了盘子上字符的重要部分。然而,现在这并不是真正的问题,因为我们不担心识别角色:我们只想隔离他们所在的区域。所以下一步是继续删除段,更具体地说是那些没有与数字的相同 Y 轴对齐的段。在这个切割过程中幸存下来的轮廓是:

enter image description here enter image description here enter image description here enter image description here

  • 这好多了,此时一个新的 std::vector<cv::Point>创建用于存储绘制所有这些线段所需的所有像素坐标。这是创建 cv::RotatedRect 所必需的这就是允许我们创建 bounding box 的原因还有crop the image :

enter image description here enter image description here enter image description here enter image description here

从现在开始,您可以使用裁剪后的图像来执行您自己的技术并轻松分割车牌的字符。

这是 C++ 代码:

#include <iostream>
#include <vector>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/imgproc_c.h>

/* The code has an outter loop where every iteration processes one of the four input images */

std::string files[] = { "plate1.jpg", "plate2.jpg", "plate3.jpg", "plate4.jpg" };
cv::Mat imgs[4];
for (int a = 0; a < 4; a++)
{
/* Load input image */

imgs[a] = cv::imread(files[a]);
if (imgs[a].empty())
{
std::cout << "!!! Failed to open image: " << imgs[a] << std::endl;
return -1;
}

/* Convert to grayscale */

cv::Mat gray;
cv::cvtColor(imgs[a], gray, cv::COLOR_BGR2GRAY);

/* Histogram equalization improves the contrast between dark/bright areas */

cv::Mat equalized;
cv::equalizeHist(gray, equalized);
cv::imwrite(std::string("eq_" + std::to_string(a) + ".jpg"), equalized);
cv::imshow("Hist. Eq.", equalized);

/* Bilateral filter helps to improve the segmentation process */

cv::Mat blur;
cv::bilateralFilter(equalized, blur, 9, 75, 75);
cv::imwrite(std::string("filter_" + std::to_string(a) + ".jpg"), blur);
cv::imshow("Filter", blur);

/* Threshold to binarize the image */

cv::Mat thres;
cv::adaptiveThreshold(blur, thres, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 15, 2); //15, 2
cv::imwrite(std::string("thres_" + std::to_string(a) + ".jpg"), thres);
cv::imshow("Threshold", thres);

/* Remove small segments and the extremelly large ones as well */

std::vector<std::vector<cv::Point> > contours;
cv::findContours(thres, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

double min_area = 50;
double max_area = 2000;
std::vector<std::vector<cv::Point> > good_contours;
for (size_t i = 0; i < contours.size(); i++)
{
double area = cv::contourArea(contours[i]);
if (area > min_area && area < max_area)
good_contours.push_back(contours[i]);
}

cv::Mat segments(gray.size(), CV_8U, cv::Scalar(255));
cv::drawContours(segments, good_contours, -1, cv::Scalar(0), cv::FILLED, 4);
cv::imwrite(std::string("segments_" + std::to_string(a) + ".jpg"), segments);
cv::imshow("Segments", segments);

/* Examine the segments that survived the previous lame filtering process
* to figure out the top and bottom heights of the largest segments.
* This info will be used to remove segments that are not aligned with
* the letters/numbers of the plate.
* This technique is super flawed for other types of input images.
*/

// Figure out the average of the top/bottom heights of the largest segments
int min_average_y = 0, max_average_y = 0, count = 0;
for (size_t i = 0; i < good_contours.size(); i++)
{
std::vector<cv::Point> c = good_contours[i];
double area = cv::contourArea(c);
if (area > 200)
{
int min_y = segments.rows, max_y = 0;
for (size_t j = 0; j < c.size(); j++)
{
if (c[j].y < min_y)
min_y = c[j].y;

if (c[j].y > max_y)
max_y = c[j].y;
}
min_average_y += min_y;
max_average_y += max_y;
count++;
}
}
min_average_y /= count;
max_average_y /= count;
//std::cout << "Average min: " << min_average_y << " max: " << max_average_y << std::endl;

// Create a new vector of contours with just the ones that fall within the min/max Y
std::vector<std::vector<cv::Point> > final_contours;
for (size_t i = 0; i < good_contours.size(); i++)
{
std::vector<cv::Point> c = good_contours[i];
int min_y = segments.rows, max_y = 0;
for (size_t j = 0; j < c.size(); j++)
{
if (c[j].y < min_y)
min_y = c[j].y;

if (c[j].y > max_y)
max_y = c[j].y;
}

// 5 is to add a little tolerance from the average Y coordinate
if (min_y >= (min_average_y-5) && (max_y <= max_average_y+5))
final_contours.push_back(c);
}

cv::Mat final(gray.size(), CV_8U, cv::Scalar(255));
cv::drawContours(final, final_contours, -1, cv::Scalar(0), cv::FILLED, 4);
cv::imwrite(std::string("final_" + std::to_string(a) + ".jpg"), final);
cv::imshow("Final", final);


// Create a single vector with all the points that make the segments
std::vector<cv::Point> points;
for (size_t x = 0; x < final_contours.size(); x++)
{
std::vector<cv::Point> c = final_contours[x];
for (size_t y = 0; y < c.size(); y++)
points.push_back(c[y]);
}

// Compute a single bounding box for the points
cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));
cv::Rect roi;
roi.x = box.center.x - (box.size.width / 2);
roi.y = box.center.y - (box.size.height / 2);
roi.width = box.size.width;
roi.height = box.size.height;

// Draw the box at on equalized image
cv::Point2f vertices[4];
box.points(vertices);
for(int i = 0; i < 4; ++i)
cv::line(imgs[a], vertices[i], vertices[(i + 1) % 4], cv::Scalar(255, 0, 0), 1, CV_AA);
cv::imwrite(std::string("box_" + std::to_string(a) + ".jpg"), imgs[a]);
cv::imshow("Box", imgs[a]);

// Crop the equalized image with the area defined by the ROI
cv::Mat crop = equalized(roi);
cv::imwrite(std::string("crop_" + std::to_string(a) + ".jpg"), crop);
cv::imshow("crop", crop);

/* The cropped image should contain only the plate's letters and numbers.
* From here on you can use your own techniques to segment the characters properly.
*/

cv::waitKey(0);
}

有关使用 OpenCV 进行车牌识别的更完整、更可靠的方法,请查看 Mastering OpenCV with Practical Computer Vision Projects , 第 5 章Source code is available on Github!

关于image - 从图像中分割字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26270821/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com