将给定 "type" 文件中的图像加载到 OpenCV Mat 中?

Loading image from file as given "type" into an OpenCV Mat?

我最近开始使用 OpenCV 的 Java 绑定来制作一个快速而肮脏的项目来进行模板匹配。基本上我试图将一组 jpg 图像(保存在 MS Paint 中)读入 Mats,然后使用模板匹配从使用 Java.Robot.

拍摄的屏幕截图中找到它们的位置

进行模板匹配时抛出此错误

OpenCV Error: Assertion failed ((depth == CV_8U || depth == CV_32F) 
&& type == _templ.type() && _img.dims() <= 2) in cv::matchTemplate

it looks like the issue is that the two Mats I am trying to use do not have the same "type". What I am not sure of is what this refers to. I assume it is the Mats CvType, if I print out the CvType of the image and template I get a type() of 4 == CvType.CV_32SC1 对于我的模板,我得到 20 == CvType.CV_32SC3type()

但是我感觉这样不对type()我在比较,我感觉它指的是数据是如何存储在Mat中的数据类型?但是我没有很好的链接来支持这一点,只是来自许多 SO 搜索的记忆。

这是我将 jpg 图像加载到 Mat

中的代码
Mat pic_ = Imgcodecs.imread("MyPath\image.jpg");
pic_.convertTo(pic_, CvType.CV_32SC1); 

此处第二行将我的 type() 从 20 变为 16,但根据我的上一条评论,我认为这不是更改 Mat 以匹配图像的正确方法? ... 因为 convertTo'ing 这个 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 Robot 创建的 BufferedImageBufferedImage.TYPE_3BYTE_BGR 类型,在尝试获取像素数据时出现错误 "DataBufferInt cannot be cast to 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

正如@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