Comparing Mat types
Hello.
I am attempting to use open cv to compare the Mat representations of a local image versus an image extracted via URL. I'm interested in getting a binary output, true if the web image matches in every way with the local image, false otherwise.
To test, I downloaded a web image locally, and attempted to compare the original web image against the local copy using the overloaded equals method of the Mat type.
The dimensions of both Mat objects appear to be the same in the output, but the equals method reports that the two Mat objects are not the same.
I'm kind of at a loss. Was I using the Mat.equals method outside the context it was intended?
Source code follows:
public static void main (String args[]) throws IOException { ImageExtractor imageRepository = new ImageExtractor("filepath", "urlPath");
System.out.println(imageRepository.getLocalImage()); System.out.println(imageRepository.getWebImage());
System.out.println(imageRepository.getLocalImage().equals(imageRepository.getWebImage())); }
public class ImageExtractor { private Mat webImage; private Mat localImage;
public ImageExtractor(String filepath, String urlPath) throws IOException
{
localImage = convertLocalImageToMat(filepath);
webImage = convertWebImageToMat(urlPath);
}
// webimage conversion
private Mat convertWebImageToMat(String url) throws IOException
{
InputStream input = new URL(url).openStream();
Mat resultImage = readInputStreamIntoMat(input);
return resultImage;
}
private Mat readInputStreamIntoMat(InputStream inputStream) throws IOException {
// Read into byte-array
byte[] temporaryImageInMemory = readStream(inputStream);
// Decode into mat. Use any IMREAD_ option that describes your image appropriately
Mat outputImage = Imgcodecs.imdecode(new MatOfByte(temporaryImageInMemory), Imgcodecs.IMREAD_ANYCOLOR);
return outputImage;
}
private byte[] readStream(InputStream stream) throws IOException {
// Copy content of the image to byte-array
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = stream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] temporaryImageInMemory = buffer.toByteArray();
buffer.close();
stream.close();
return temporaryImageInMemory;
}
// local image conversion
private Mat convertLocalImageToMat(String filepath)
{
return Imgcodecs.imread(filepath);
}
public Mat getWebImage()
{
return webImage;
}
public Mat getLocalImage()
{
return localImage;
}
}
" true if the web image matches in every way with the local image" --- that may be a misassumption. images get re-compressed on the web, there's lossy jpegs and whatnot.
So, I compared the cells of the matrices against each other, and unsurprisingly, every single cell did not match.
Hmmm...I wasn't aware that images get recompressed on the web.
I could have the source programmatically download and save the image from the specified URL, and compare that newly downloaded image against the local image, but I'm unsure if I'll run into the same misassumption as before.
So, I tried downloading the image at the url into a local file, and tried comparing the freshly downloaded file against another copy of the same file via the Mat.equals method: all cells of both matrices still did not match.
I then constructed two Mat objects from the same local file, and attempted comparison of both Mat objects that should have been equal (since they were constructed from the same file) through the Mat.equals method: all cells of both Mat objects did not match.
So, here's the question. If I constructed two different Mat objects from the same exact image file, why would each cell value be different in both Mat objects?
if you use jpeg images, this is pretty normal (that's what "lossy" compression means)
imho, you need a different measurement. compare() or anything bitwise exact won't ever work.
maybe like: sum(absdiff(a,b)) < some_threshold ?
PNG images, actually.
I'll try using a threshold of some sort.