使用opencv检测字符断裂
最近工厂需要检测出工价表面是否存在喷码是否断裂的情况,断裂的图片如图所示:
需要检测出断裂的字符以及断裂的位置,输出如下图:
实现思想:
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);
}
使用opencv检测字符断裂相关推荐
- 使用OpenCV检测相机与目标的角度和距离
使用OpenCV检测相机与目标的角度和距离 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一个表格 设 ...
- opencv 车牌字符分割 ANN网络识别字符
opencv 车牌字符分割 ANN网络识别字符 原文参考:https://www.cnblogs.com/chenzhefan/p/7629441.html 最近在复习OPENCV的知识,学习ca ...
- 使用Python,OpenCV检测摄像机到标记对象的距离
使用Python,OpenCV检测摄像机到标记对象的距离 1. 效果图 2. 三角形相似性是什么? 3. 三角形相似性检测距离原理 4. 使用Python,OpenCV检测标记对象 5. 源码 参考 ...
- 使用Python和OpenCV检测图像中的条形码
使用Python和OpenCV检测图像中的条形码 1. 效果图 2. 算法的步骤 3. 源码 参考 这篇博客将介绍使用计算机视觉和图像处理技术进行条形码检测的必要步骤,并演示使用Python编程语言和 ...
- OpenCV检测图像轮廓
轮廓只不过是图像中连接的曲线,或者图像中连通部分的边界,轮廓通常以图像中的边缘来计算,但是,边缘和轮廓的区别在于轮廓是闭合的,而边缘可以是任意的.边缘的概念局限于点及其邻域像素,轮廓将目标作为整体进行 ...
- opencv检测矩形
参考:使用OpenCV检测图像中的矩形_知来者逆的博客-CSDN博客_opencv检测图像中的矩形 1.得到原始图像之后,代码处理的步骤是: (1)滤波增强边缘. (2)分离图像通道,并检测边缘. ( ...
- python opencv 检测特定颜色
python opencv 检测特定颜色 import cv2 import numpy as npcap = cv2.VideoCapture(0)# set blue thresh 设置HSV中蓝 ...
- python opencv检测人脸
python opencv检测人脸 文章目录: 一.opencv检测一张图片 二.opencv摄像头实时检测人脸 一.opencv检测一张图片 opencv检测人脸分成三部分: 1.图片转换成灰色(降 ...
- 使用Python和OpenCV检测图片上的条形码
这篇博文的目的是应用计算机视觉和图像处理技术,展示一个条形码检测的基本实现.我所实现的算法本质上基于StackOverflow 上的这个问题,浏览代码之后,我提供了一些对原始算法的更新和改进. 首先需 ...
最新文章
- R语言dplyr包coalesce函数处理缺失值(missing value)实战
- 设计师之歌 --【死了都要改】
- R语言--查看数据类型+类型判断
- 秒杀系统优化方案(下)吐血整理
- Storm,Spark和Samza
- linux驱动初探之字符驱动
- 记一次使用 vue-admin-template 的优化历程
- 【Java】Hello world
- [外星与文明]外星人的离开对地球有什么影响?
- 8个常用的wx小程序 UI 组件库,社区、电商、工具各类都有!
- vue 获取汉字的全拼、简拼、首拼
- thinkphp 官网教程
- 鲲鹏大数据解决方案拆解:用硬实力跨越技术与应用的鸿沟
- 钉钉群机器人关键词自动回复_企业微信营销机器人怎么接入?
- java 转换html标签,java转化html标签
- 云栖独栋别墅_绿野云溪花海独栋别墅
- uniapp vue 微信小程序 前端 直传华为云对象存储OBS
- Android 内存检测工具
- 苏州大学计算机课程与资源,苏州大学计算机学院2018-2019学年第一学期研究生课课程表...
- python求二叉树高度_求二叉树高度代码报错,求大佬解答