我想识别信用卡上的数字。更糟糕的是,源图像不能保证高质量。OCR是通过神经网络实现的,但这不应该是这里的主题。
当前的问题是图像预处理。由于信用卡可以有背景和其他复杂的图形,文本不像扫描文档那样清晰。我做了边缘检测实验(Canny Edge,Sobel),但没有那么成功。此外,计算灰度图像和模糊图像之间的差异(如在Remove background color in image processing for OCR中所述)并不会导致OCRable结果。
我认为大多数方法都失败了,因为特定数字与其背景之间的对比不够强烈。可能需要将图像分割成块,并为每个块找到最佳的预处理方案?
您有什么建议如何将源转换为可读的二进制图像?边缘检测是要走的路还是我应该坚持基本的颜色阈值?
这里是一个灰度阈值处理方法的示例(在这里,我显然对结果不满意):
原始图像:

灰度图像:

缩影图像:

谢谢你的建议,瓦伦丁
发布于 2012-02-22 16:50:16
我处理这个问题的方法是把卡片分成不同的部分。没有很多独特的信用卡可以开始(MasterCard,Visa,列表是由您决定的),所以您可以像下拉列表一样指定它是哪一张信用卡。这样,您就可以消除并指定像素区域:
示例:
只处理底部20像素的区域,从左到右的30像素到底部的30像素(创建一个矩形)-这将覆盖所有的MasterCards。
当我使用图像处理程序(有趣的项目)时,我打开了图片的对比度,将其转换为灰度,将每个RGB值的平均值取为1个像素,并将其与周围的像素进行比较:
示例:
PixAvg[i,j] = (Pix.R + Pix.G + Pix.B)/3
if ((PixAvg[i,j] - PixAvg[i,j+1])>30)
boolEdge == true;30是你希望你的形象有多鲜明。差异越小,容忍度就越低。
在我的项目中,为了查看边缘检测,我创建了一个独立的布尔数组(包含来自boolEdge的值)和一个像素数组。像素数组中只填充了黑白点。它从布尔数组中获得值,其中boolEdge = true是一个白点,boolEdge = false是一个黑点。最后,你会得到一个像素数组(完整的图片),它只包含白色和黑色的点。
从那里,更容易检测到一个数字从哪里开始,一个数字在哪里结束。
发布于 2014-02-25 10:18:09
在我的实现中,我尝试从这里使用代码:http://rnd.azoft.com/algorithm-identifying-barely-legible-embossed-text-image/结果更好,但还不够.我发现很难找到贴图卡的正确对角。
(void)processingByStrokesMethod:(cv::Mat)src dst:(cv::Mat*)dst {
cv::Mat tmp;
cv::GaussianBlur(src, tmp, cv::Size(3,3), 2.0); // gaussian blur
tmp = cv::abs(src - tmp); // matrix of differences between source image and blur iamge
//Binarization:
cv::threshold(tmp, tmp, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
//Using method of strokes:
int Wout = 12;
int Win = Wout/2;
int startXY = Win;
int endY = src.rows - Win;
int endX = src.cols - Win;
for (int j = startXY; j < endY; j++) {
for (int i = startXY; i < endX; i++) {
//Only edge pixels:
if (tmp.at<unsigned char="">(j,i) == 255)
{
//Calculating maxP and minP within Win-region:
unsigned char minP = src.at<unsigned char="">(j,i);
unsigned char maxP = src.at<unsigned char="">(j,i);
int offsetInWin = Win/2;
for (int m = - offsetInWin; m < offsetInWin; m++) {
for (int n = - offsetInWin; n < offsetInWin; n++) {
if (src.at<unsigned char="">(j+m,i+n) < minP) {
minP = src.at<unsigned char="">(j+m,i+n);
}else if (src.at<unsigned char="">(j+m,i+n) > maxP) {
maxP = src.at<unsigned char="">(j+m,i+n);
}
}
}
//Voiting:
unsigned char meanP = lroundf((minP+maxP)/2.0);
for (int l = -Win; l < Win; l++) {
for (int k = -Win; k < Win; k++) {
if (src.at<unsigned char="">(j+l,i+k) >= meanP) {
dst->at<unsigned char="">(j+l,i+k)++;
}
}
}
}
}
}
///// Normalization of imageOut:
unsigned char maxValue = dst->at<unsigned char="">(0,0);
for (int j = 0; j < dst->rows; j++) { //finding max value of imageOut
for (int i = 0; i < dst->cols; i++) {
if (dst->at<unsigned char="">(j,i) > maxValue)
maxValue = dst->at<unsigned char="">(j,i);
}
}
float knorm = 255.0 / maxValue;
for (int j = 0; j < dst->rows; j++) { //normalization of imageOut
for (int i = 0; i < dst->cols; i++) {
dst->at<unsigned char="">(j,i) = lroundf(dst->at<unsigned char="">(j,i)*knorm);
}
} https://stackoverflow.com/questions/9398374
复制相似问题