上篇我们大致了解了如何运用OpenCV在Android上进行图片但简单处理
Android OpenCV应用篇二:图片处理
接下来我们就运用之前的一些相关技术来搞点事情:
如何从一张图片中将文字提取出来?
前言
在开始之前,我们先来看一个字
高
可以看到,这个字体是上中下结构,相应的,我们的汉字还有左中右结构等等,我们如何在识别的过程中,不会吧这些特殊结构的字体识别成多个?
看一下高字的腐蚀效果:
当然,我们传统的都是认为白纸黑字,但实际上并不一定都是这一,所以在此之前我们需要进行排除环境影响,如何处理?
这里也是用到我们上一篇但知识:
- 降噪
- 阈值化
开始我们的文字提取
OK前面大致介绍了一下基本操作,我们下面总结一下,然后开始实现
步骤:
- 阈值化
- 腐蚀
- 降噪
- 文字区域检测
- 文字提取
第一步:阈值化&腐蚀
由于字体大小,或其他一些字体间的间距、行宽等影响,不同的字体图片可能需要用到等腐蚀效果不同,这里我们只进行原理上的处理,我选了一张比较适中等图片进行操作演示。
/**
* 阈值化,并腐蚀
* @param src
*/
private void erode(Mat src) {
// 阈值化
Imgproc.threshold(src, src, 100, 255, Imgproc.THRESH_BINARY);
// Imgproc.adaptiveThreshold(opMat,opMat,255.0,Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY,3,0.0);
Mat erodeKernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5, 5));
Imgproc.erode(src, src, erodeKernel);
}
第一步处理效果:
可以看出,完全转换成了白纸黑字,标题上等红色背景框完全除去掉了。但可以看出有明显的噪声,比如身字左下角有一个点等。
第二步 滤波降噪
这里我们采用最为简单的中值滤波进行降噪
/**
* 采用中值滤波进行降噪
*
* @param src
*/
private void medianBlur(Mat src) {
Imgproc.medianBlur(src, src, 7);
}
处理后的效果:
第三步 区域检测
区域检测,这里我们采用检测连通区域再根据联通区域计算边框的方式进行检测,当然,还有其他的一些检测方法,比如轮廓检测法、边缘检测等方法。
- 连通区域检测
- Rect边框计算
连通区域检测
首先进行连通区域检测,这里我们采用种子填充法进行连通区域检测,比较常用的还有两遍扫描法等
种子填充法
详情请查阅 百度百科
下面开始进行种子填充算法,为了方便展示填充效果,我将每个连通区域都进行了重新赋值,这样就可以得到一个不同颜色值的联通区域展示图。具体代码如下:
/**
* 种子填充法进行联通区域检测
*/
private Mat seedFill(Mat binImg, Mat src) {
// 用来记录连通区域都数据图
Mat lableImg = new Mat();
// 这个是用来展示连通区域都效果图。
Mat showMat = new Mat(binImg.size(), CvType.CV_8UC3);
// 不需要记录额外都数据,一个通道就够了。
binImg.convertTo(lableImg, CvType.CV_32SC1);
int rows = lableImg.rows();
int cols = lableImg.cols();
double lable = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
// 获取种子像素点
double[] data = lableImg.get(r, c);
if (data == null || data.length < 1) {
continue;
}
if (data[0] == 255) {
// 不是我们要都种子像素,继续
// 展示图背景设置为白色
showMat.put(r, c, 255, 255, 255);
continue;
}
if (data[0] != 0) {
// 已经标记过了,继续
continue;
}
// 走到这里说明找到了新的种子像素点,新的填充开始
lable++;
// 随机生成一个颜色,用来填充展示图
double[] color = {
Math.random() * 255, Math.random() * 255, Math.random() * 255};
// 开始种子填充
LinkedList<Point> neighborPixels = new LinkedList<>();
neighborPixels.push(new Point(r, c));
while (!neighborPixels.isEmpty()) {
Point curPx = neighborPixels.pop();
int row = (int) curPx.x;
int col = (int) curPx.y;
lableImg.put(row, col, lable);
showMat.put(row, col, color);
// 左边
double[] left = lableImg.get(row, col - 1);