I want to show 2, 3 or more images in the same window.
My problem is how to put the second, third image just on the right side (above, left or upper) the main image.
Try this code (see my comments):
Mat img = imread("lena.JPG");
CV::Mat chann[3], all; // creating
split(img, chann); // split an image into their color channel and n keep them inside
a 3 element array called chann
imshow("ppl", img);
hconcat(chann, 3, all); // joining the images together in a horizontal manner, the
array, number of array, and the destination
imshow("B :: G :: R",all); // this just the little help i could provide
The GUI included with OpenCV is pretty limited, if you need to do anything complicated, you really should use a GUi framework such as QT or VC++ on windows
I implemented this very recently. So thought of sharing it. It uses C++ API. The code is self-explanatory (hopefully).
/**
* @brief makeCanvas Makes composite image from the given images
* @param vecMat Vector of Images.
* @param windowHeight The height of the new composite image to be formed.
* @param nRows Number of rows of images. (Number of columns will be calculated
* depending on the value of total number of images).
* @return new composite image.
*/
cv::Mat makeCanvas(std::vector<cv::Mat>& vecMat, int windowHeight, int nRows) {
int N = vecMat.size();
nRows = nRows > N ? N : nRows;
int edgeThickness = 10;
int imagesPerRow = ceil(double(N) / nRows);
int resizeHeight = floor(2.0 * ((floor(double(windowHeight - edgeThickness) / nRows)) / 2.0)) - edgeThickness;
int maxRowLength = 0;
std::vector<int> resizeWidth;
for (int i = 0; i < N;) {
int thisRowLen = 0;
for (int k = 0; k < imagesPerRow; k++) {
double aspectRatio = double(vecMat[i].cols) / vecMat[i].rows;
int temp = int( ceil(resizeHeight * aspectRatio));
resizeWidth.push_back(temp);
thisRowLen += temp;
if (++i == N) break;
}
if ((thisRowLen + edgeThickness * (imagesPerRow + 1)) > maxRowLength) {
maxRowLength = thisRowLen + edgeThickness * (imagesPerRow + 1);
}
}
int windowWidth = maxRowLength;
cv::Mat canvasImage(windowHeight, windowWidth, CV_8UC3, Scalar(0, 0, 0));
for (int k = 0, i = 0; i < nRows; i++) {
int y = i * resizeHeight + (i + 1) * edgeThickness;
int x_end = edgeThickness;
for (int j = 0; j < imagesPerRow && k < N; k++, j++) {
int x = x_end;
cv::Rect roi(x, y, resizeWidth[k], resizeHeight);
cv::Size s = canvasImage(roi).size();
// change the number of channels to three
cv::Mat target_ROI(s, CV_8UC3);
if (vecMat[k].channels() != canvasImage.channels()) {
if (vecMat[k].channels() == 1) {
cv::cvtColor(vecMat[k], target_ROI, CV_GRAY2BGR);
}
} else {
vecMat[k].copyTo(target_ROI);
}
cv::resize(target_ROI, target_ROI, s);
if (target_ROI.type() != canvasImage.type()) {
target_ROI.convertTo(target_ROI, canvasImage.type());
}
target_ROI.copyTo(canvasImage(roi));
x_end += resizeWidth[k] + edgeThickness;
}
}
return canvasImage;
}
Here is sample output.
The answer depends on which interface you are using (C or C++). General workflow is
cv::Mat
for C++, IplImage*
for C) big enough to accomodate your composed imageMat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
constructor to get a cv::Mat
pointing to a subimage of your original window, then use the copyTo
method to copy your small image into the big oneOr just use:
Mat a, Mat b, Mat dst // a,b loaded
cv::hconcat(a, b, dst) // horizontal
cv::vconcat(a, b, dst) // vertical
Mat dst -> | a | b |
or do it with vector:
std::vector<cv::Mat> matrices = {
a, b
};
hconcat(matrices, dst);
You can find the answer on the OpenCV Wiki:
https://github.com/opencv/opencv/wiki/DisplayManyImages
:-)