将文件中的图像从“文件”中加载到OpenCV Mat中?

时间:2016-01-18 16:36:06

标签: java opencv image-processing bufferedimage

我最近开始使用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 tellBufferedImage创建的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

1 个答案:

答案 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即可!