根据轮廓点坐标生成mask(java + opencv实现)

1. 背景

实验室的项目中有一个需求是:用户在前端界面的一张图片上勾勒出自己感兴趣的区域,后台根据该区域的顶点坐标生成一个mask。实际场景如下图所示。
在这里插入图片描述

2. 方法

目前已找到两种方式实现上述需求:

  • 使用OpenCV提供的API;
  • 利用OpenCV填充的思想(漫水填充法)自己写代码实现。

2.1 使用OpenCV提供的API实现

2.1.1 依赖文件下载

在使用OpenCV提供的API之前,需要事先配置好环境。先从opencv官网上下载所需的版本,我是在windows平台下进行开发的,所以直接下载的.exe文件(下载速度很慢且不稳地,可能需要科学上网),如果是在Linux上进行开发,可能需要下载源码进行编译。下载完成后运行,将文件解压到合适的目录下即可。对于Java开发,只需要找到解压目录下的这些文件即可。
opencv解压文件

2.1.1 IDE环境配置

我本人使用的是eclipse进行的开发,以下是eclipse中的配置方式。
首先在工程目录下新建一个“lib”文件夹,将之前解压的“opencv-412.jar”复制到该文件夹下。添加完成后,选中该jar包并点击右键,选择“Build path” —> “Add to Build Path”,将该jar包添加到项目中。在这里插入图片描述
然后右键刚添加的jar包,选择"Build Path" --> “Cofigure Build Path”。
在这里插入图片描述
在弹出的对话框中双击“Native library location”,在“location path”输入之前解压的目录下的x64文件的路径,因为该路径下含有opencv的动态库文件opencv-xxx.dll,Linux下编译完成后是opencv-xxx.so文件,java程序将通过JNI去调用opencv C++的动态库中的方法去实现相关功能。
在这里插入图片描述
点击"ok"和apply即完成了以上配置的过程。

2.1.2 代码

opencv中完成区域填充的关键函数是fillpoly函数,其实现填充的原理是“漫水填充法”。废话不多说,直接上代码。

/**
 * 通过 OpenCV 创建一张图的mask
 * @author tong
 */
public class CreateMaskByOpenCV {
   
	/**
	 * 创建一个掩膜
	 * @param width: 图片的宽度
	 * @param height: 图片的高度
	 * @param filePath: 文件保存的路径
	 * @param type: 文件的类型
	 * @param points: 轮廓的顶点
	 * @throws IOException 
	 */
	public static void create(int width, int height, String filePath, String type, List<Point> points) throws IOException {
   
		// 对输入的点进行预处理
		List<org.opencv.core.Point> list = new ArrayList<>();
		for (Point p : points) {
   
			list.add(new org.opencv.core.Point(p.getxAxis(), p.getyAxis()));
		}
		
		// 创建掩膜区域
		List<MatOfPoint> maskArea = new ArrayList<>();
		MatOfPoint maskPoints = new MatOfPoint();
		maskPoints.fromList(list);
		maskArea.add(maskPoints);
		
		// 构建掩膜
		Mat mask = new Mat(new Size(width, height), CvType.CV_8UC3, new Scalar(0, 0, 0));
		Imgproc.fillPoly(mask, maskArea, new Scalar(255, 255, 255));
		
		// 保存图片
		imWrite(filePath, mask, type);
	}
	
	
	/**
	 * 保存图片
	 * @param filePath
	 * @param mat
	 * @return
	 */
	private static boolean imWrite(String filePath, Mat mat, String type) {
   
		FileOutputStream fos = null;
		try {
   
			// 预处理
			File file = new File(filePath);
			if (file.exists()) file.delete();
			file.createNewFile();
			
			
			MatOfByte matOfByte = new MatOfByte();
			Imgcodecs.imencode("." + type, mat, matOfByte);
			matOfByte.toArray();
			
			// 将字节列表转为字节数组
			byte[] bytes = matOfByte.toArray();
		
			// 写文件
			fos = new FileOutputStream(new File(filePath));
			fos.write(bytes);
			
			// 返回结果
			return true;
		} catch (IOException e) {
   
			System.out.println("图片保存失败: " + e.getMessage());
		} finally {
   
			try {
   
				fos.close();
			} catch (IOException e) {
   
				System.out.println("图片保存失败: " + e.getMessage());
			}
		}
		return false;
	}
	
	
	public static void main(String[] args) {
   
		long start = System.currentTimeMillis();
		
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
		
		String filePath = "E:/projects/Java/json/智能配置文件/海康设备1_IPCamera1/mask1.bmp";
		List<Point> points = new ArrayList<>();
		points.add(new Point(334, 362));
		points.add(new Point(906, 300));
		points.add(new Point(934, 309));
		points.add(new Point(875, 1075));
		points.add(new Point(696, 1075));
		points.add
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是使用JavaOpenCV实现数字识别的步骤: 1.准备数据集:首先需要准备一组手写数字的图像数据集,包括数字0-9。可以使用MNIST数据集或自己手写数字的图像数据集。 2.提取特征:使用OpenCV提取数字图像的特征,可以使用HOG特征或LBP特征。 3.训练模型:使用机器学习算法,如SVM或神经网络,对提取的特征进行训练,生成数字识别模型。 4.测试模型:使用测试集对训练好的模型进行测试,评估模型的准确率。 5.应用模型:将训练好的模型应用到实际场景中,对输入的手写数字图像进行识别。 以下是一个使用JavaOpenCV实现数字识别的示例代码: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfFloat; import org.opencv.core.MatOfInt; import org.opencv.core.Rect; import org.opencv.core.Size; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import org.opencv.ml.SVM; public class DigitRecognizer { private SVM svm; public DigitRecognizer() { svm = SVM.create(); svm.setType(SVM.C_SVC); svm.setKernel(SVM.RBF); svm.setGamma(0.5); svm.setC(1); } public void train(String trainDataPath, String labelsPath) { // 读取训练数据和标签 Mat trainData = Imgcodecs.imread(trainDataPath, Imgcodecs.IMREAD_GRAYSCALE); Mat labels = Imgcodecs.imread(labelsPath, Imgcodecs.IMREAD_GRAYSCALE); // 提取HOG特征 MatOfFloat descriptors = new MatOfFloat(); Size winSize = new Size(20, 20); Size blockSize = new Size(10, 10); Size blockStride = new Size(5, 5); Size cellSize = new Size(5, 5); int nbins = 9; MatOfInt histSize = new MatOfInt(nbins); MatOfInt fromTo = new MatOfInt(0, nbins); MatOfInt channels = new MatOfInt(0); Imgproc.HOGDescriptor hog = new Imgproc.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins); Rect roi = new Rect(0, 0, 20, 20); for (int i = 0; i < trainData.rows(); i++) { Mat digit = trainData.row(i).reshape(1, 20); MatOfFloat descriptor = new MatOfFloat(); hog.compute(digit.submat(roi), descriptor, winSize, blockSize, blockStride); descriptors.push_back(descriptor); } // 训练模型 svm.train(descriptors, SVM.RAW_OUTPUT, labels); // 保存模型 svm.save("svm.xml"); } public int predict(String digitPath) { // 读取待识别的数字图像 Mat digit = Imgcodecs.imread(digitPath, Imgcodecs.IMREAD_GRAYSCALE); // 提取HOG特征 MatOfFloat descriptor = new MatOfFloat(); Size winSize = new Size(20, 20); Size blockSize = new Size(10, 10); Size blockStride = new Size(5, 5); Size cellSize = new Size(5, 5); int nbins = 9; MatOfInt histSize = new MatOfInt(nbins); MatOfInt fromTo = new MatOfInt(0, nbins); MatOfInt channels = new MatOfInt(0); Imgproc.HOGDescriptor hog = new Imgproc.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins); Rect roi = new Rect(0, 0, 20, 20); hog.compute(digit.submat(roi), descriptor, winSize, blockSize, blockStride); // 使用模型进行预测 float[] result = new float[1]; svm.predict(descriptor, result, SVM.RAW_OUTPUT); return (int) result[0]; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值