小老板给了新任务,看来要研究一下java的图像处理了。
目前最基本的目标是:任意图片的文字提取。
还没有明确的思路,先简单调研一下看看别人都怎么搞的吧。
首先是搭环境。
1. 下载安装opencv。
去opencv官网下载并且解压缩就好了。目前我还没搞清版本2.4和3.3有什么区别。
这里有的帖子说要加path,我就顺手加了。$opencvpath$/build/java/x64
2. 在IDEA中新建项目。
这就没啥说的了,新建一个java项目就可以。
3. 设置jar库和dll位置。
在project structure中新建一个java库,然后引用到$opencvpath$/build/java/*.jar
然后在run configurations里的VM option里根据opencv库解压缩的位置添加:-Djava.library.path=D:\MyLibrary\opencv-3.3.0-vc14\build\java\x64;D:\MyLibrary\opencv-3.3.0-vc14\build\java\x64
最后,在新建的类里面,一定要包含以下代码:
static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
然后就可以了…………最后一步大概折腾了我半个小时…………直到看到一篇帖子提到这段代码,我才意识到是少了这个。
然后就是先随便抓一篇代码练练手。
这里参考了这篇文章 http://blog.csdn.net/huobanjishijian/article/details/63685503
然后面临的问题就是:网上常见的opencv代码都是用c++或者python实现的。但是目前看要求,我这套还是得在java上跑,所以就需要把代码改写成java版本的。
这里用到了opencv的官方手册。https://docs.opencv.org/java/2.4.11/
反正就是一条一条对,但是仍然有对不上的。
最后代码如下:
import org.opencv.core.*; import java.util.ArrayList; import java.util.List; import static org.opencv.core.CvType.CV_8U; import static org.opencv.imgcodecs.Imgcodecs.imread; import static org.opencv.imgcodecs.Imgcodecs.imwrite; import static org.opencv.imgproc.Imgproc.*; /** * Created by wangzhao on 2017/10/24. */ public class test { static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args){ System.out.println("hello"); System.out.println(Core.VERSION); Mat mat=imread("test.jpg"); System.out.println(mat); detect(mat); } public static void detect(Mat img) { Mat gray=new Mat(); cvtColor(img, gray, COLOR_BGR2GRAY); Mat pro=preprocess(gray); List<MatOfPoint> region=findTextRegion(pro); System.out.println(region.size()); drawContours(img, region, -1, new Scalar(0, 255, 0), 2); imwrite("contours.png", img); } public static Mat preprocess(Mat gray) { Mat sobel=new Mat(); Sobel(gray, sobel, CV_8U, 1, 0); Mat binary=new Mat(); threshold(sobel, binary, 0, 255, THRESH_OTSU+THRESH_BINARY); Mat element1=getStructuringElement(MORPH_RECT, new Size(30,9)); Mat element2=getStructuringElement(MORPH_RECT, new Size(24,6)); Mat dilation=new Mat(); dilate(binary, dilation, element2); Mat erosion=new Mat(); erode(dilation, erosion, element1); Mat dilation2=new Mat(); dilate(erosion, dilation2, element2); imwrite("binary.png", binary); imwrite("dilation.png", dilation); imwrite("erosion.png", erosion); imwrite("dilation2.png", dilation2); return dilation2; } public static List<MatOfPoint> findTextRegion(Mat img) { Mat hierarchy=new Mat(); List<MatOfPoint> contours=new ArrayList<>(); findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); // for (MatOfPoint cnt:contours) { // double area=contourArea(cnt); // if (area<1000) { // continue; // } // double epsilon=0.001*arcLength(new MatOfPoint2f(cnt.toArray()), true); // MatOfPoint2f approx=new MatOfPoint2f(); // approxPolyDP(new MatOfPoint2f(cnt.toArray()), approx, epsilon, true); // RotatedRect rect=minAreaRect(new MatOfPoint2f(cnt.toArray())); // } return contours; } }
好消息是:现在用java跑opencv已经没有大的问题了。
但是仍然有以下的问题需要解决:
1. 一些c++或python的opencv库提供的函数,在java中并不存在。对于存在的函数,由于python不需要声明变量类型,所以改写成java的版本也效率很低。不过这至少可以work。
2. 这次初步尝试的文本提取方法,对于稍微复杂一点的情况就无法实现了。需要调研寻找可靠的文字提取算法。
以上是今天尝试的收获。