12

I am trying to display 2 images horizontally adjacent to each other in the same window using OpenCV.

I have tried using adjustROI function for this.Image 1 has 1088 pixels width and 2208 pixels height while Image 2 has 1280 pixels width and 2208 pixels height.Please suggest what could be wrong in the code below.All I am getting is an image of size Image2 with content from Image2 as well.

Mat img_matches=Mat(2208,2368,imgorig.type());//set size as combination of img1 and img2
img_matches.adjustROI(0,0,0,-1280); 
imgorig.copyTo(img_matches);
img_matches.adjustROI(0,0,1088,1280);
imgorig2.copyTo(img_matches);
mpenkov
  • 21,621
  • 10
  • 84
  • 126
code4fun
  • 2,661
  • 9
  • 25
  • 39

3 Answers3

28

EDIT: Here's how I'd do what you want to do:

Mat left(img_matches, Rect(0, 0, 1088, 2208)); // Copy constructor
imgorig.copyTo(left);
Mat right(img_matches, Rect(1088, 0, 1280, 2208)); // Copy constructor
imgorig2.copyTo(right);

The copy constructors create a copy of the Mat header that points to the ROI defined by each of the Rects.

Full code:

#include <cv.h>
#include <highgui.h>

using namespace cv;

int
main(int argc, char **argv)
{
    Mat im1 = imread(argv[1]);
    Mat im2 = imread(argv[2]);
    Size sz1 = im1.size();
    Size sz2 = im2.size();
    Mat im3(sz1.height, sz1.width+sz2.width, CV_8UC3);
    Mat left(im3, Rect(0, 0, sz1.width, sz1.height));
    im1.copyTo(left);
    Mat right(im3, Rect(sz1.width, 0, sz2.width, sz2.height));
    im2.copyTo(right);
    imshow("im3", im3);
    waitKey(0);
    return 0;
}

Compiles with:

g++ foo.cpp -o foo.out `pkg-config --cflags --libs opencv`

EDIT2:

Here's how it looks with adjustROI:

#include <cv.h>
#include <highgui.h>

using namespace cv;

int
main(int argc, char **argv)
{
    Mat im1 = imread(argv[1]);
    Mat im2 = imread(argv[2]);
    Size sz1 = im1.size();
    Size sz2 = im2.size();
    Mat im3(sz1.height, sz1.width+sz2.width, CV_8UC3);
    // Move right boundary to the left.
    im3.adjustROI(0, 0, 0, -sz2.width);
    im1.copyTo(im3);
    // Move the left boundary to the right, right boundary to the right.
    im3.adjustROI(0, 0, -sz1.width, sz2.width);
    im2.copyTo(im3);
    // restore original ROI.
    im3.adjustROI(0, 0, sz1.width, 0);
    imshow("im3", im3);
    waitKey(0);
    return 0;
}

You have to keep track of what the current ROI is, and the syntax for moving the ROI around can be a little un-intuitive. The result is the same as the first block of code.

mpenkov
  • 21,621
  • 10
  • 84
  • 126
  • 1
    This doesn't work either.I think the first 2 parameters need to be zero in both cases because the height of both images is (almost) same and i just need to place them side by side. – code4fun Oct 30 '12 at 06:05
  • I've just realized adjustROI behaves slightly differently to what I'm used to (the old C cvSetImageROI). Check out my updated answer. – mpenkov Oct 30 '12 at 06:12
  • i had tried something similar.The copy constructor is giving a copy of the original matrix,so when I try to print "img_matches" it still is blank.While printing "left" and "right" separately gives those images – code4fun Oct 30 '12 at 06:19
  • The constructor copies the header of the matrix, not the underlying data. The underlying data remains shared with the original image. So when you copyTo left/right, you're actually copying to the original image. I've just tried it -- it works. See my updated answer for full code. – mpenkov Oct 30 '12 at 06:31
  • I got bored and tried using `adjustROI`. Looking at your question, you were very close to finding the solution by yourself. The only thing you did wrong was forgetting to reset the ROI. – mpenkov Oct 30 '12 at 09:42
  • None of these work. Just make the code a function, pass two images, and you can see it doesn't work. The first method gives a black window, second one just displays only second image. – Abhinandan Dubey May 27 '18 at 22:44
9

As the height (rows of Mat) of the images are same, function hconcat maybe used to horizontally concatenate two images (Mat) and thus can be used to display them side-by-side in the same window. OpenCV doc.
It works with both grayscale and color images. The number of color channels in the source matrices must be same.

Mat im1, im2; // source images im1 and im2

Mat newImage;
hconcat(im1, im2, newImage);  // <---- place image side by side

imshow("Display side by side", newImage);
waitKey(0);

For the sake of completeness, vconcat can be similarly used for vertical concatenation.

Sumit Dey
  • 324
  • 3
  • 12
  • with the hconcat the mats need to be of the same dimensions – BossShell Apr 26 '18 at 10:01
  • @BossShell By dimensions, if you mean color channels (not the dimensions of matrix), then yes, they need to be same (will update answer). To be explicit: for `hconcat`, the columns of the source mats can be different. – Sumit Dey Nov 27 '19 at 15:48
6

Here's a solution inspired in @misha's answer.

#include <cv.h>
#include <highgui.h>

using namespace cv;

int
main(int argc, char **argv)
{
    Mat im1 = imread(argv[1]);
    Mat im2 = imread(argv[2]);
    Size sz1 = im1.size();
    Size sz2 = im2.size();
    Mat im3(sz1.height, sz1.width+sz2.width, CV_8UC3);
    im1.copyTo(im3(Rect(0, 0, sz1.width, sz1.height)));
    im2.copyTo(im3(Rect(sz1.width, 0, sz2.width, sz2.height)));
    imshow("im3", im3);
    waitKey(0);
    return 0;
}

Instead of using the copy constructor, this solution uses Mat::operator()(const Rect& roi). While both solutions are O(1), this solution seems cleaner.

Fábio Perez
  • 23,850
  • 22
  • 76
  • 100