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.
I want to create something like this, using OpenCV.
---------------
| | |
| | |
-------开发者_JAVA百科--------
| | |
| | |
---------------
Thanks in advance Jorge
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.
You can find the answer on the OpenCV Wiki:
https://github.com/opencv/opencv/wiki/DisplayManyImages
:-)
Or 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);
The answer depends on which interface you are using (C or C++). General workflow is
- Create an image (
cv::Mat
for C++,IplImage*
for C) big enough to accomodate your composed image - Copy your images into the big image
- C++: Use the
Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
constructor to get acv::Mat
pointing to a subimage of your original window, then use thecopyTo
method to copy your small image into the big one - C: set a ROI in the big image and copy your small image into it
- C++: Use the
- Display your big 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
精彩评论