我最近开始使用OpenCV的Java绑定来创建一个快速而又脏的项目来进行模板匹配。基本上我试图将一组jpg图像(保存在MS Paint中)读入Mat
,然后使用模板匹配从Java.Robot
拍摄的屏幕截图中找到它们的位置。
当需要进行模板匹配时,会抛出此错误
OpenCV Error: Assertion failed ((depth == CV_8U || depth == CV_32F)
&& type == _templ.type() && _img.dims() <= 2) in cv::matchTemplate
After searching看起来问题是我尝试使用的两个Mat
没有相同的“类型”。我不确定的是这是指什么。我假设它是Mat
s CvType
,如果我打印出图片和模板的CvType
,我的模板4 == CvType.CV_32SC1
type()
得到type()
20 == CvType.CV_32SC3
。
但是我觉得这不是正确的type()
我想比较,我觉得它指的是数据如何存储在Mat
中的数据类型?但是我没有很好的联系支持这个只是对许多SO搜索的记忆。
以下是我的jpg图片加载到Mat
Mat pic_ = Imgcodecs.imread("MyPath\\image.jpg");
pic_.convertTo(pic_, CvType.CV_32SC1);
这里第二行将我的type()
从20变为16,但根据我的上一条评论,我不认为这是改变Mat
以匹配图像的正确方法吗? 。因为convertTo
使这个Mat
与屏幕截图的类型匹配(下面)不能解决错误?
以下是我创建图片的方式Mat
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenShot = rob.createScreenCapture(screenRect);
Mat screenImage = bufferedImageToMat(screenShot);
所以我首先使用Java.Robot.createScreenCapture
截取屏幕截图,然后使用
Mat
private Mat bufferedImageToMat(BufferedImage inBuffImg)
{
BufferedImage image = new BufferedImage(inBuffImg.getWidth(), inBuffImg.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d= image.createGraphics();
g2d.drawImage(inBuffImg, 0, 0, null);
g2d.dispose();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_32SC1);
int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
From what I could tell由BufferedImage
创建的Robot
类型为BufferedImage.TYPE_3BYTE_BGR
,在尝试获取像素数据时,会给出错误“DataBufferInt无法转换为DataBufferByte”。因此,根据链接的问题,我将BufferedImage
重新标记为类型BufferedImage.TYPE_INT_RGB
,并将数据作为DataBufferInt
提取出来。
总而言之,我应该尝试匹配Mat.type()
还是我的问题出在其他地方?如果不在其他地方,我如何更改Mat
中的任何一个,以便它们可以与Imgproc.matchTemplate
正确使用?
我觉得最简单的解决方案是转换从文件加载的图片以匹配屏幕截图Mat
?
编辑:提供错误的确切代码部分位于
之下// Mat imageTemplate is a function argument; the loaded jpg image
// Take a picture of the screen
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenShot = rob.createScreenCapture(screenRect);
Mat screenImage = bufferedImageToMat(screenShot);
// Create the result matrix
int result_cols = screenImage.cols() - imageTemplate.cols() + 1;
int result_rows = screenImage.rows() - imageTemplate.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32SC1);
newStatus("ScreenType: " + screenImage.type());
newStatus("TemplaType: " + imageTemplate.type());
// Choose a matching method
int matchMethod = Imgproc.TM_SQDIFF_NORMED;
// Do the Matching and Normalize
Imgproc.matchTemplate(screenImage, imageTemplate, result, matchMethod);
// Error occurs on previous line
答案 0 :(得分:3)
正如@Miki在评论中指出的那样,答案是获得与图像和模板匹配的通道类型。我最终改变了我的bufferedImageToMat
功能。
private Mat bufferedImageToMat(BufferedImage inBuffImg)
{
BufferedImage image = new BufferedImage(inBuffImg.getWidth(), inBuffImg.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d= image.createGraphics();
g2d.drawImage(inBuffImg, 0, 0, null);
g2d.dispose();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
我的模板以CvType.CV_8UC3
的形式读取,因此只需使用此类型从屏幕图像创建Mat
即可!