Java OpenCV学习之Mat的基本操作详解

目录
  • 使用OpenCV时你需要补充的知识
  • Mat对象
  • Mat划线
  • Mat在己有图片上加圆圈
    • ImageShowAddCircle.java
    • ImageViewer.java
  • Mat与Image互转
    • OpenCVUtil.java
  • Mat使用blur图片

环境好了,我们就可以进入正文了。

在之前入门一、二中分别已经有画图的两个例子了。但没有细节展开我们的代码和OpenCV到底在干什么。

使用OpenCV时你需要补充的知识

你需要熟练使用Java Swing,或者是其它任何一门语言中关于GUI方面的编程。

我们这用的是OpenCV Java,因此对于Java Swing必须熟练。你可以安装eclipse 中的windowbuilder来帮助你做Swing的编程。

至于Java Swing中的界面、Frame、Panel、Button以及Layout,这块在“JDK核心技术卷1、卷2”中已有详细描述,我就不多此一举了。

Mat对象

OpenCV用来存储图像,很多时候都会用到这个Mat方法。数字图像可看做一个数值矩阵, 其中的每一个元素表明一个像素点。Mat在 OpenCV 中表示的是 N 维稠密矩阵,与稠密矩阵相对的是稀疏矩阵(只存储非零的像素值)。

Mat 类包含两部分,一是 矩阵头 (matrix header),二是 矩阵指针 (pointer to matrix),部分矩阵头以下:blog

int  flags;  // signaling the contents of the matrix
int  dims;   // dimensions
int  rows, cols;  // rows and columns
MatSize  size;  //
MatStep  step;  //

具体不作进一步展开,但我们要会使用这个Mat。

因此今天以Mat来做几个小练习。

Mat划线

package org.mk.opencv;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;

public class DrawLine {

	public static void main(String[] args) {
		// 载入dll(必须先加载)
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
		Mat truth = new Mat(500, 500, CvType.CV_8UC3);

		byte[] line = new byte[truth.channels() * truth.width()];

		for (int i = 0; i < line.length; i++) {
			line[i] = 125;
		}
		truth.put(250, 0, line);

		HighGui.imshow("原图", truth);
		HighGui.waitKey(0);

	}

}

记得OpenCV上手都有一句“System.loadLibrary(Core.NATIVE_LIBRARY_NAME);”,是因为OpenCV Java虽然使用的是“opencv-343.jar”,实际它会去调用“opencv_java343.dll”,并且opencv_java343.dll有依赖,它会去找它自己在Windows的控制面板->系统变量->path中的依赖的那些opencv编译出来的包。

我不喜欢把opencv_java343.dll所依赖的这些DLL放到windows的安装目录的System32目录下。

因为你把这些dll放在system32目录下,和你直接在System的path下加入这些dll效果是一样的。

HighGui是一个OpenCV自带的“内嵌面板”。

有时我也会自己写JFrame来做“展示”。如下面这个例子。

Mat在己有图片上加圆圈

ImageShowAddCircle.java

package org.mk.opencv;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

public class ImageShowAddCircle {
	public static void main(String[] args) {
		// 载入dll(必须先加载)
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
		// 将文件读入为OpenCV的Mat格式。注意测试时,路径不要包括中文
		Mat src = Imgcodecs.imread("D:\\opencv-demo\\1.jpg");
		if (src.dataAddr() == 0) {
			System.out.println("打开文件出错");
		}
		ImageViewerAddCircle imageViewer = new ImageViewerAddCircle(src, "图片上加圆圈");
		imageViewer.imshow();
	}
}

ImageViewer.java

package org.mk.opencv;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

import org.mk.opencv.util.OpenCVUtil;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;

public class ImageViewerAddCircle {
	private JLabel imageView;
	private Mat image;
	private String windowName;

	public ImageViewerAddCircle(Mat image) {
		this.image = image;
	}

	/**
	 * @param image      要显示的mat
	 * @param windowName 窗口标题
	 */
	public ImageViewerAddCircle(Mat image, String windowName) {
		this.image = image;
		this.windowName = windowName;
	}

	/**
	 * 图片显示,并使用opencv的ImgProc.circle在图片上加两个圆圈
	 */
	public void imshow() {
		setSystemLookAndFeel();
		//在图上画圆
		Imgproc.circle(image, new Point(50, 50), 40, new Scalar(255, 0, 0), 2);
		//在图上画另一个圆
		Imgproc.circle(image, new Point(50, 100), 80, new Scalar(0, 255, 0), 5);
		//展示画了圆的图像
		Image loadedImage = OpenCVUtil.matToImage(image);
		JFrame frame = createJFrame(windowName, image.width(), image.height());
		imageView.setIcon(new ImageIcon(loadedImage));
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 用户点击窗口关闭
	}

	private void setSystemLookAndFeel() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
	}

	private JFrame createJFrame(String windowName, int width, int height) {
		JFrame frame = new JFrame(windowName);
		imageView = new JLabel();
		final JScrollPane imageScrollPane = new JScrollPane(imageView);
		imageScrollPane.setPreferredSize(new Dimension(width, height));
		frame.add(imageScrollPane, BorderLayout.CENTER);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		return frame;
	}
}

它显示的效果如下:

它会在一个图片上(未加圆圈前)

显示带两个圆圈的画(加了圆圈后)

Mat与Image互转

由于我们经常使用Swing组件,Swing中有一个imageView.setIcon方法或者是setImage方法,它要求的是输入一个java.awt.Image对象。

那么Mat和Image经常会互转,因此我们有一套互转的小工具类如下:

OpenCVUtil.java

package org.mk.opencv.util;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.io.File;

import org.apache.log4j.Logger;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

public class OpenCVUtil {
	private static Logger logger = Logger.getLogger(OpenCVUtil.class);

	public static Image matToImage(Mat matrix) {
		int type = BufferedImage.TYPE_BYTE_GRAY;
		if (matrix.channels() > 1) {
			type = BufferedImage.TYPE_3BYTE_BGR;
		}
		int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
		byte[] buffer = new byte[bufferSize];
		matrix.get(0, 0, buffer); // 获取所有的像素点
		BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
		final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
		System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
		return image;
	}

	public static BufferedImage matToBufferedImage(Mat matrix) {
		int cols = matrix.cols();
		int rows = matrix.rows();
		int elemSize = (int) matrix.elemSize();
		byte[] data = new byte[cols * rows * elemSize];
		int type;
		matrix.get(0, 0, data);
		switch (matrix.channels()) {
		case 1:
			type = BufferedImage.TYPE_BYTE_GRAY;
			break;
		case 3:
			type = BufferedImage.TYPE_3BYTE_BGR;
			// bgr to rgb
			byte b;
			for (int i = 0; i < data.length; i = i + 3) {
				b = data[i];
				data[i] = data[i + 2];
				data[i + 2] = b;
			}
			break;
		default:
			return null;
		}
		BufferedImage image2 = new BufferedImage(cols, rows, type);
		image2.getRaster().setDataElements(0, 0, cols, rows, data);
		return image2;
	}

	public static Mat bufferedImageToMat(BufferedImage bi) {
		Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
		byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
		mat.put(0, 0, data);
		return mat;
	}
}

Mat使用blur图片

package org.mk.opencv;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Blur {
	public static void main(String[] args) {
		try {
			System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

			Mat src = Imgcodecs.imread("D:/opencv-demo/1.jpg");
			if (src.empty()) {
				throw new Exception("no file");
			}

			Mat dst = src.clone();

			Imgproc.blur(src, dst, new Size(800, 600));
			Imgcodecs.imwrite("D:/opencv-demo/blur.jpg", dst);
		} catch (Exception e) {
			System.out.println("出错啦:" + e);
		}
	}

}

它把一张原来的未blur处理的图片,变成了如下这样

结束今天的博客,下一篇会讲“认脸”。认脸和识脸是两个课题,我们一步步来。目前网上99%的教程只能到达认脸这一步,即这是一个脸。但不代表这是谁?这是谁就叫“识脸”。

以上就是Java OpenCV学习之Mat的基本操作详解的详细内容,更多关于Java OpenCV Mat的资料请关注我们其它相关文章!

(0)

相关推荐

  • OpenCV 通过Mat遍历图像的方法汇总

    目录 方法一.直接对图像像素修改.at<typename>(i,j) 二.用指针.ptr<uchar>(k)来遍历输入图像,数组[]生成输出图像 三.用指针.ptr<uchar>(k)来遍历输入图像,指针方式生成输出图像 四.用指针.ptr<uchar>(k)来遍历输入图像,指针方式结合位运算生成输出图像 五.用指针.ptr<uchar>(k)来遍历输入图像,指针方式结合取模运算生成输出图像 六.连续图像isContinuous()函数方法. 七

  • OpenCV中的cv::Mat函数将数据写入txt文件

    在使用opencv进行图像处理的过程中,经常会涉及到将文件中的数据读入到cv::Mat中,或者将cv::Mat中的数据写入到txt文件中. 下面就介绍一种我常用的将cv::Mat中的数据写入到txt文件中的方法,具体见代码: void writeMatToFile(cv::Mat& m, const char* filename) { std::ofstream fout(filename); if (!fout) { std::cout << "File Not Opene

  • java+opencv实现人脸识别功能

    背景:最近需要用到人脸识别,但又不花钱使用现有的第三方人脸识别接口,为此使用opencv结合java进行人脸识别(ps:opencv是开源的,使用它来做人脸识别存在一定的误差,效果一般). 1.安装opencv 官网地址:https://opencv.org/ , 由于官网下载速度是真的慢 百度网盘: 链接: https://pan.baidu.com/s/1RpsP-I7v8pP2dkqALDw7FQ 提取码: pq7v 如果是官网下载,就无脑安装就行了,安装完毕后. 将图一的两个文件复制到图

  • OpenCV cv.Mat与.txt文件数据的读写操作

    本篇文章主要介绍了OpenCV cv.Mat 与 .txt 文件数据的读写操作,小编觉得挺不错的,现在分享给大家. 1.按OpenCV格式实现的 .txt 文件读写 可以用 cvSave 和 cvLoad 实现,格式和 .xml/.yml 的差不多,不过如果专用与 OpenCV 的数据读写,还是用  .xml/.yml 文件格式较好,我比较喜欢 .yml 格式,可读性非常棒. 用 cvSave 和 cvLoad 读写 .txt 文件,其实现方式和数据格式与 .yml 文件基本一致. 例如:cvS

  • Java OpenCV图像处理之背景切换

    目录 实现步骤 函数详解 示例代码 效果图 实现步骤 1 读取原图片 2 获取原图片的mask 3 获取原图片需要获取的ROI 4 获取新背景的mask 5 融合 3,5 函数详解 示例代码 package com.xu.opencv; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.Scalar; import org.opencv.highgui.HighGui; import o

  • Java OpenCV图像处理之背景消除

    目录 实现步骤 主要代码 效果图 实现步骤 1.获取视频 2.设置形态学结构 3.创建Video.createBackgroundSubtractorMOG2() 4.提取模型 BS 5.进行形态学变换 6.展示结果 主要代码 package com.xu.opencv; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import ja

  • Java OpenCV学习之Mat的基本操作详解

    目录 使用OpenCV时你需要补充的知识 Mat对象 Mat划线 Mat在己有图片上加圆圈 ImageShowAddCircle.java ImageViewer.java Mat与Image互转 OpenCVUtil.java Mat使用blur图片 环境好了,我们就可以进入正文了. 在之前入门一.二中分别已经有画图的两个例子了.但没有细节展开我们的代码和OpenCV到底在干什么. 使用OpenCV时你需要补充的知识 你需要熟练使用Java Swing,或者是其它任何一门语言中关于GUI方面的

  • OpenCV学习之图像梯度算子详解

    目录 1.Sobel算子 2.Scharr算子 3.laplacian算子 本文是OpenCV图像视觉入门之路的第12篇文章,本文详细的介绍了图像梯度算子的各种操作,例如:Sobel算子Scharr算子laplacian算子等操作. 1.Sobel算子 Sobel算子是一种图像边缘检测算子,它是一种空间滤波器,可以检测图像中的边缘,而梯度运算是一种求导数的方法,可以用来检测图像中的局部变化. import cv2 import numpy as np from numpy import unic

  • OpenCV学习之图像形态学处理详解

    目录 1.腐蚀操作 2.膨胀操作 3.开闭运算 4.梯度运算 5.Top Hat Black Hat运算 本文是OpenCV图像视觉入门之路的第11篇文章,本文详细的在图像形态学进行了图像处理,例如:腐蚀操作.膨胀操作.开闭运算.梯度运算.Top Hat Black Hat运算等操作. 1.腐蚀操作 从下面代码中可以看到有三幅腐蚀程度不同的图,腐蚀越严重像素就越模糊 import cv2 import numpy as np from numpy import unicode if __name

  • Java OpenCV图像处理之仿射变换,透视变换,旋转详解

    目录 1 仿射变换 2 透视变换 3 图像旋转 1 仿射变换 仿射变换:一种二维坐标到二维坐标的线性变换,它保持二维图像的平直性与平行性,即变换后直线依然是直线,平行的线依然平行. package com.xu.opencv.image; import java.io.File; import java.util.ArrayList; import java.util.List; import org.opencv.core.Mat; import org.opencv.core.MatOfPo

  • java高并发之线程的基本操作详解

    目录 新建线程 终止线程 线程中断 等待(wait)和通知(notify) 挂起(suspend)和继续执行(resume)线程 等待线程结束(join)和谦让(yeild) 总结 新建线程 新建线程很简单.只需要使用new关键字创建一个线程对象,然后调用它的start()启动线程即可. Thread thread1 = new Thread1(); t1.start(); 那么线程start()之后,会干什么呢?线程有个run()方法,start()会创建一个新的线程并让这个线程执行run()

  • Java基础学习之反射机制原理详解

    目录 一.什么是反射 二.反射的原理 三.反射的优缺点 四.反射的用途 五.反射机制常用的类 六.反射的基本使用 一.什么是反射 (1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法.本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息. (2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM.通过反射,可

  • Spring学习笔记1之IOC详解尽量使用注解以及java代码

    在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IOC,mybatis,SpringMVC的基础知识,表单数据验证,文件上传等) 2.服务器异步发送邮件给注册用户.(学习消息队列) 3.用户登录.(学习缓存.Spring Security) 4.其他. 边学习边总结,不定时更新.项目环境为Intellij + Spring4. 一.准备工作. 1.m

  • Java web基础学习之开发环境篇(详解)

    Tomcat + Eclipse添加Java EE插件 因为之前进行Java SE学习已经配置了JDK,安装了Eclipse for Java SE,所以选择了在Eclipse上添加插件的方式来配置Web开发环境 Tomcat是免安装版,直接解压即可: Eclipse中"帮助-安装新软件",work with处选择Mars - http://download.eclipse.org/releases/mars(注意对应自己版本): 选择Web.Java EE那个选项进行安装即可,如果报

  • java学习笔记之DBUtils工具包详解

    DBUtils工具包 一.介绍 DBUtils是Apache组织开源的数据库工具类. 二.使用步骤 ①.创建QueryRunner对象 ②.调用update()方法或者query()方法执行sql语句 三.构造方法及静态方法 QueryRunner类 1.构造方法 ①.无参构造 QueryRunner qr =new QueryRunner(); 使用无参构造的时候,调用update方法和query方法时就需要使用带Connection 类型参数的重载形式 ②.有参构造 QueryRunner

  • Git基础学习之分支基本操作详解

    目录 1.创建分支 (1)创建分支 (2)图示理解 2.查看分支列表 3.分支切换 4.查看所有分支的最后一个提交 5.删除分支 1.创建分支 (1)创建分支 Git 是怎么创建新分支的呢? 很简单,就是要创建一个可以移动的新的指针. 比如,创建一个testing分支, 你需要使用命令:git branch testing. 示例: # 1.查看本地版本库历史提交 L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master) $ gi

随机推荐