使用opencv检测字符断裂

来源:互联网 发布:梁家辉 演技 知乎 编辑:程序博客网 时间:2024/04/28 02:23

最近工厂需要检测出工价表面是否存在喷码是否断裂的情况,断裂的图片如图所示:

需要检测出断裂的字符以及断裂的位置,输出如下图:


实现思想:

1.分割出字符的外轮廓

2.计算每个外轮廓的连通域个数,多于两个的为断裂,设置i和j的阈值(正上方区域面积与其他连通域面积的比),但是还是有误检(如果其他字符也在正上方发生断裂,且面积比符合阈值),暂时还没有解决。

3.计算断裂的位置,连通域的最短距离的中点。

代码:

component.h

#ifndef __COMPONENT__
#define __COMPONENT__
#include <stdlib.h>


#define CALL_LabelComponent(x,y,returnLabel) { STACK[SP] = x;  \
STACK[SP + 1] = y; STACK[SP + 2] = returnLabel; SP += 3; goto START; }


#define RETURN { SP -= 3;                \
switch (STACK[SP + 2])    \
{                       \
case 1: goto RETURN1;  \
case 2: goto RETURN2;  \
case 3: goto RETURN3;  \
case 4: goto RETURN4;  \
default: return;        \
}                       \
}
#define X (STACK[SP-3])
#define Y (STACK[SP-2])

void LabelComponent(unsigned short* STACK, unsigned short width, unsigned short height,
unsigned char* input, int* output, int labelNo, unsigned short x, unsigned short y);
void LabelImage(unsigned short width, unsigned short height, unsigned char* input, int* output);

#endif

splitimg.h

#ifndef __SPLITIMG__
#define __SPLITIMG__

#include <opencv2/opencv.hpp>  
#include <vector>

using namespace cv;
using namespace std;

typedef struct LINE_S
{
Point start;
Point end;
} LINE;

float pt_length(Point & pt1, Point & pt2);
// all input image must be black(0) frontground
bool get_slplit_line(Mat &src, vector<LINE> &line_arr);
bool get_split_box_big(Mat &src, vector<Rect> &rect_arr_big);
bool get_split_box_small(Mat &src, vector<Rect> &rect_arr_small);
bool compute_point(Mat &src, Mat &mask, Rect &rect, vector<Point> &point_arr);

#endif


component.cpp


#include "component.h"

void LabelComponent(unsigned short* STACK, unsigned short width, unsigned short height,
unsigned char* input, int* output, int labelNo, unsigned short x, unsigned short y)
{
STACK[0] = x;
STACK[1] = y;
STACK[2] = 0;  /* return - component is labelled */
int SP = 3;
int index;
START: /* Recursive routine starts here */
index = X + width*Y;
if (input[index] == 0) RETURN;   /* This pixel is not part of a component */
if (output[index] != 0) RETURN;   /* This pixel has already been labelled  */
output[index] = labelNo;

if (X > 0) CALL_LabelComponent(X - 1, Y, 1);   /* left  pixel */
RETURN1:


if (X < width - 1) CALL_LabelComponent(X + 1, Y, 2);   /* right pixel */
RETURN2:


if (Y > 0) CALL_LabelComponent(X, Y - 1, 3);   /* upper pixel */
RETURN3:


if (Y < height - 1) CALL_LabelComponent(X, Y + 1, 4);   /* lower pixel */
RETURN4:


RETURN;
}
// input image must with black(0) backgroud and white frontground(1~255)

void LabelImage(unsigned short width, unsigned short height, unsigned char* input, int* output)
{
unsigned short* STACK = (unsigned short*)malloc(3 * sizeof(unsigned short)*(width*height + 1));

int labelNo = 0;
int index = -1;
for (unsigned short y = 0; y < height; y++)
{
for (unsigned short x = 0; x < width; x++)
{
index++;
if (input[index] == 0) continue;   /* This pixel is not part of a component */
if (output[index] != 0) continue;   /* This pixel has already been labelled  */
/* New component found */
labelNo++;
LabelComponent(STACK, width, height, input, output, labelNo, x, y);
}
}

free(STACK);
}


splitimg.cpp


#include "splitimg.h"

float pt_length(Point & pt1, Point & pt2)
{
return sqrt(((float)pt1.x - (float)pt2.x)*((float)pt1.x - (float)pt2.x) + ((float)pt1.y - (float)pt2.y)*((float)pt1.y - (float)pt2.y));
}


/****************************************************************************************************



***********************************    usage of get_split_line    ***********************************


/*vector<LINE> line_arr;
get_slplit_line(testImg, line_arr);


vector<LINE>::iterator iter = line_arr.begin();


for (; iter != line_arr.end(); iter++)
{

line(testImg, iter->start, iter->end, Scalar(0), 1, 8);

}

*****************************************************************************************************/
bool get_slplit_line(Mat &src, vector<LINE> &line_arr)
{
vector<int> coor;


for (int ii = 0; ii != src.rows; ii++)
{
int sum_black = 0;

for (int j = 0; j != src.cols; j++)
{
if (src.at<uchar>(ii, j) == 0)
sum_black++;
}

if (sum_black >= 1)
{
coor.push_back(ii);
}

}

if (coor.size() == 0) 
return false;

vector<int> result;
vector<int>::iterator iter = coor.begin();
result.push_back(*iter);

int temp = *iter;

for (; iter != coor.end() - 1; iter++)
{
if (*(iter + 1) - temp == 1)
{
temp = *(iter + 1);
}
else
{
result.push_back(temp);
result.push_back(*(iter + 1));
temp = *(iter + 1);
}
}
result.push_back(*(coor.end() - 1));

vector<int>::iterator it = result.begin();
for (; it != result.end(); it++)
{
LINE line;
line.start = Point(0, *it);
line.end = Point(src.cols, *it);
line_arr.push_back(line);
}
return true;
}


bool get_split_box_big(Mat &src, vector<Rect> &rect_arr_big)
{
vector<LINE> line_arr;


if (!get_slplit_line(src, line_arr))
{
return false;
}


vector<LINE>::iterator iter = line_arr.begin();


for (; iter != line_arr.end(); iter+=2)
{

vector<int> col_line;
for (int ii = 0; ii != src.cols; ii++)
{
int sum_black = 0;


for (int j = iter->start.y; j != (iter + 1)->start.y; j++)
{
if (src.at<uchar>(j, ii) == 0)
sum_black++;
}


if (sum_black >= 1)
{
col_line.push_back(ii);
}
}
if (col_line.size() == 0) 
return false;

vector<int> col_line_result;

vector<int>::iterator col_iter = col_line.begin();
col_line_result.push_back(*col_iter);


int temp = *col_iter;
for (; col_iter != col_line.end() - 1; col_iter++)
{
if (*(col_iter + 1) - temp == 1)
{
temp = *(col_iter + 1);
}
else
{
col_line_result.push_back(temp);
col_line_result.push_back(*(col_iter + 1));
temp = *(col_iter + 1);
}
}
col_line_result.push_back(*(col_line.end() - 1));

vector<int>::iterator col_line_result_it = col_line_result.begin();
for (; col_line_result_it != col_line_result.end(); col_line_result_it+=2)
{
int row_s = iter->start.y;
int row_e = (iter + 1)->start.y;
int col_s = *col_line_result_it;
int col_e = *(col_line_result_it + 1);

rect_arr_big.push_back(Rect(col_s, row_s, (col_e - col_s + 1), (row_e - row_s + 1)));
}

}
return true;
}
bool get_split_box_small(Mat &src, vector<Rect> &rect_arr_small)
{
vector<Rect> rect_arr;


if (!get_split_box_big(src, rect_arr))
{
return false;
}

vector<Rect>::iterator iter = rect_arr.begin();
for (; iter != rect_arr.end(); iter ++)
{
vector<int> row_line;
for (int ii = iter->y; ii < iter->y + iter->height; ii++)
{
int sum_black = 0;

for (int j = iter->x; j < iter->x + iter->width; j++)
{
if (src.at<uchar>(ii, j) == 0)
sum_black++;
}

if (sum_black >= 1)
{
row_line.push_back(ii);
}
}
if (row_line.size() == 0)
return false;

vector<int> row_line_result;

vector<int>::iterator row_iter = row_line.begin();
row_line_result.push_back(*row_iter);


int temp = *row_iter;


for (; row_iter != row_line.end() - 1; row_iter++)
{
if (*(row_iter + 1) - temp == 1)
{
temp = *(row_iter + 1);
}
else
{
row_line_result.push_back(temp);
row_line_result.push_back(*(row_iter + 1));
temp = *(row_iter + 1);
}
}
row_line_result.push_back(*(row_line.end() - 1));

vector<int>::iterator row_line_result_it = row_line_result.begin();
for (; row_line_result_it != row_line_result.end(); row_line_result_it += 2)
{
int row_s = *row_line_result_it; 
int row_e = *(row_line_result_it + 1);
int col_s = iter->x;
int col_e = iter->x + iter->width - 1;
rect_arr_small.push_back(Rect(col_s, row_s, (col_e - col_s + 1), (row_e - row_s + 1)));
}


}
return true;
}

bool compute_point(Mat &src, Mat &mask, Rect &rect, vector<Point> &point_arr)
{
map<int, Point> p_begin;
map<int, Point> p_end;
map<int, Point >::iterator b_it;
map<int, Point >::iterator e_it;
map<int, vector<Point>> area;
map<int, vector<Point>>::iterator area_it;
vector<Point>::iterator point_it1;
vector<Point>::iterator point_it2;

for (int ii = rect.y; ii != (rect.y + rect.height); ii++)
{


for (int j = rect.x; j != (rect.x + rect.width); j++)
{
if (mask.at<int>(ii, j) != 0)
{
b_it = p_begin.find(mask.at<int>(ii, j));
if (b_it == p_begin.end())
{
p_begin[mask.at<int>(ii, j)] = Point(j, ii);
}
else
{
p_end[mask.at<int>(ii, j)] = Point(j, ii);
}
area[mask.at<int>(ii, j)].push_back(Point(j, ii));
}
}
}

if (area.size() > 1)
{
area_it = area.begin();
if ((float)area_it->second.size() / (float)(++area_it)->second.size() < 0.2 && area.size() == 2)
{
return false;
}
else
{
area_it = area.begin();
for (; area_it != --area.end(); area_it++)
{
vector<Point> tmp1 = area_it->second;
vector<Point> tmp2 = (++area_it)->second;
point_it1 = tmp1.begin();

float pt_len = 100000.;
Point st;
Point ed;

for (; point_it1 != tmp1.end(); point_it1++)
{
point_it2 = tmp2.begin();
for (; point_it2 != tmp2.end(); point_it2++)
{
if (pt_length(*point_it1, *point_it2) < pt_len)
{
pt_len = pt_length(*point_it1, *point_it2);
st = *point_it1;
ed = *point_it2;
}
}
}
int tmp_x = (st.x + ed.x) / 2;
int tmp_y = (st.y + ed.y) / 2;

point_arr.push_back(Point(tmp_x, tmp_y));

--area_it;

}
}
}
else
{
return false;
}
return true;
}


main.cpp


#include <opencv2/opencv.hpp>  
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"


#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>  
#include <time.h>

#include "template.h"
#include "component.h"
#include "splitimg.h"


using namespace std;
using namespace cv;

int main(int argc, char **argv)
{
Mat testImg = imread("11.jpg");
clock_t       start, finish;
double       elapsed_time;
start = clock();

/*imshow("xx1", testImg);
waitKey(30);*/
Mat showImg = testImg.clone();

cvtColor(testImg, testImg, CV_BGR2GRAY);

threshold(testImg, testImg, 0, 255, CV_THRESH_OTSU);

Mat revert = ~testImg;

//start label Image
unsigned short W = revert.cols;
unsigned short H = revert.rows;
Mat connect_label = Mat::zeros(H, W, CV_32SC1);
LabelImage(W, H, (unsigned char*)revert.data, (int*)connect_label.data);

vector<Rect> rect_arr;
vector<Point> point_arr;
get_split_box_big(testImg, rect_arr);
vector<Rect>::iterator iter = rect_arr.begin();
for (; iter != rect_arr.end(); iter++)
{
rectangle(showImg, *iter, Scalar(0,255,0), 3, 8);
if (compute_point(testImg, connect_label, *iter, point_arr))
{
vector<Point>::iterator point_it = point_arr.begin();
for (; point_it != point_arr.end(); point_it++)
{
circle(showImg, *point_it, 10, Scalar(255, 0, 0), 3, 8);
}
}
}

finish = clock();

elapsed_time = finish - start;
printf("time:%f", elapsed_time);

        imshow("xx", testImg);
waitKey(-1);
imshow("output", showImg);
waitKey(-1);

}

1 0
原创粉丝点击