Three images are displayed in output window instead of one - c++

Hi everyone i tried using kmeans clustering to group the objects. So that i can use this clustering method to detect objects. I get output but the problem is its too slow{How can i solve this?? } and i get the output window is as shown in the below link. Three output images are displayed instead of one how can i solve this. I don't know where exactly the error lies.
http://tinypic.com/view.php?pic=30bd7dc&s=8#.VgkSIPmqqko
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( )
{
Mat src = imread( "Light.jpg", 0 );
// imshow("fff",src);
// cvtColor(src,src,COLOR_BGR2GRAY);
Mat dst;
// pyrDown(src,src,Size( src.cols/2, src.rows/2 ),4);
// src=dst;
resize(src,src,Size(128,128),0,0,1);
Mat samples(src.rows * src.cols, 3, CV_32F);
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
// for( int z = 0; z < 3; z++)
samples.at<float>(y + x*src.rows) = src.at<uchar>(y,x);
cout<<"aaa"<<endl;
int clusterCount = 15;
Mat labels;
int attempts = 2;
Mat centers;
cout<<"aaa"<<endl;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );
Mat new_image( src.size(), src.type() );
cout<<"aaa"<<endl;
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
{
int cluster_idx = labels.at<int>(y + x*src.rows,0);
new_image.at<uchar>(y,x) = centers.at<float>(cluster_idx,0);
//new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
// new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
imshow( "clustered image", new_image );
waitKey( 0 );
}

In your initial code you have to change the intermedia Mat sample from 3 channels to 1 channel if you use grayscale images.
In addition, if you change the memory ordering, it might be faster (changed to (y*src.cols + x, 0) in both places):
int main( )
{
clock_t start = clock();
Mat src = imread( "Light.jpg", 0 );
Mat dst;
resize(src,src,Size(128,128),0,0,1);
Mat samples(src.rows * src.cols, 1, CV_32F);
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
samples.at<float>(y*src.cols + x, 0) = src.at<uchar>(y,x);
int clusterCount = 15;
Mat labels;
int attempts = 2;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );
Mat new_image( src.size(), src.type() );
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
{
int cluster_idx = labels.at<int>(y*src.cols + x,0);
new_image.at<uchar>(y,x) = centers.at<float>(cluster_idx,0);
}
imshow( "clustered image", new_image );
clock_t end = clock();
std::cout << "time: " << (end - start)/(float)CLOCKS_PER_SEC << std::endl;
waitKey( 0 );
}

Related

C++ OpenCV How can I get the values of Binary Histogram image 0 and 255?

My code shows me values that are not accurate and i am not sure what else to try. My goal is to get the values of y such as rows, so that I can read the image and put it in an array. Ive looked at examples and Stack Overflow is literally my last option.
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat Rgb;
Mat Grey;
Mat image;
//Mat Histogram;
Rgb = imread("license.jpg", WINDOW_AUTOSIZE);
cvtColor(Rgb, Grey, cv::COLOR_BGR2GRAY);
threshold(Grey, image, 150, 250, THRESH_BINARY);
int histogram[255];
for (int i = 0; i < 255; i++)
{
histogram[i] = 0;
}
for (int y = 0; y < image.rows; y++)
//for (int x = 0; x < image.cols; x++)
histogram[(int)image.at<uchar>(y)]++;
//histogram[(int)image.at<uchar>(y, x)]++;
for (int i = 0; i < 255; i++)
cout << histogram[i] << " ";
// draw the histograms
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound((double)hist_w / 255);
Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(255, 255, 255));
int max = histogram[0];
for (int i = 1; i < 256; i++) {
if (max < histogram[i]) {
max = histogram[i];
}
}
for (int i = 0; i < 255; i++) {
histogram[i] = ((double)histogram[i] / max)*histImage.rows;
}
for (int i = 0; i < 255; i++)
{
line(histImage, Point(bin_w*(i), hist_h),
Point(bin_w*(i), hist_h - histogram[i]),
Scalar(0, 0, 0), 1, 8, 0);
}
imshow("Image", image);
waitKey(0);
cv::destroyAllWindows();
return 0;
}
Results have numbers like 319 and other values and I am only looking to get 0 or 255

(OpenCV Stitching) How to get better performance using OpenCV Stitcher class?

I have some problems when using Stitcher class.
First, I use ORB Feature Finder because it's faster than SURF.
but it's still slow.
Second, Stitcher class accuracy is too low.
Third, How can I get more performance by using Stitcher class?
Additional, How can I catch directions between two images?
This is my code.
Thank you.
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching.hpp"
#include "opencv2/features2d.hpp"
using namespace cv;
using namespace std;
void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location);
int main(int argc, char* argv[])
{
Mat first;
Mat second;
Mat m_first;
Mat m_second;
vector<Mat> images;
// vector<Mat> re_images;
Mat panorama;
Mat result;
unsigned long t;
t = getTickCount();
first = imread(argv[1], CV_LOAD_IMAGE_COLOR);
second = imread(argv[2], CV_LOAD_IMAGE_COLOR);
//Mat m_first = Mat::zeros( first.size(), first.type() );
//Mat m_second = Mat::zeros( second.size(), second.type() );
/*
for( int y = 0; y < first.rows; y++ ) {
for( int x = 0; x < first.cols; x++ ) {
for( int c = 0; c < 3; c++ ) {
m_first.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( 1.2*( first.at<Vec3b>(y,x)[c] ) + 20 );
}
}
}
for( int y = 0; y < second.rows; y++ ){
for( int x = 0; x < second.cols; x++ ) {
for( int c = 0; c < 3; c++ ) {
m_second.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( 1.2*( second.at<Vec3b>(y,x)[c] ) + 20 );
}
}
}
*/
//imwrite("first.png", m_first);
//imwrite("second.png", m_second);
resize(first, m_first, Size(640, 480));
resize(second, m_second, Size(640, 480));
images.push_back(m_first);
images.push_back(m_second);
Stitcher stitcher = Stitcher::createDefault(false);
//Stitcher::Status status = stitcher.stitch(imgs, pano);
//stitcher.setWarper(new PlaneWarper());
stitcher.setWarper(new SphericalWarper());
// stitcher.setWarper(new CylindricalWarper());
stitcher.setFeaturesFinder(new detail::OrbFeaturesFinder(Size(3,1),1500));
// stitcher.setRegistrationResol(0.6);
// stitcher.setSeamEstimationResol(0.1);
// stitcher.setCompositingResol(0.5);
//stitcher.setPanoConfidenceThresh(1);
stitcher.setWaveCorrection(true);
stitcher.setWaveCorrectKind(detail::WAVE_CORRECT_HORIZ);
stitcher.setFeaturesMatcher(new detail::BestOf2NearestMatcher(false,0.3));
stitcher.setBundleAdjuster(new detail::BundleAdjusterRay());
stitcher.setBlender(new detail::MultiBandBlender());
stitcher.stitch(images, panorama);
printf("%.2lf sec \n", (getTickCount() - t) / getTickFrequency() );
Rect rect(panorama.cols / 2 - 320, panorama.rows / 2 - 240, 640, 480);
Mat subimage = panorama(rect);
Mat car = imread("car.png");
overlayImage(subimage, car, result, cv::Point(320 - (car.cols / 2), 240 - (car.rows / 2 )));
imshow("panorama", result);
// resize(panorama, result, Size(640, 480));
imwrite("result.jpg", result);
waitKey(0);
return 0;
}
void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location)
{
background.copyTo(output);
// start at the row indicated by location, or at row 0 if location.y is negative.
for(int y = std::max(location.y , 0); y < background.rows; ++y)
{
int fY = y - location.y; // because of the translation
// we are done of we have processed all rows of the foreground image.
if(fY >= foreground.rows)
break;
// start at the column indicated by location,
// or at column 0 if location.x is negative.
for(int x = std::max(location.x, 0); x < background.cols; ++x)
{
int fX = x - location.x; // because of the translation.
// we are done with this row if the column is outside of the foreground image.
if(fX >= foreground.cols)
break;
// determine the opacity of the foregrond pixel, using its fourth (alpha) channel.
double opacity =
((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3])
/ 255.;
// and now combine the background and foreground pixel, using the opacity,
// but only if opacity > 0.
for(int c = 0; opacity > 0 && c < output.channels(); ++c)
{
unsigned char foregroundPx =
foreground.data[fY * foreground.step + fX * foreground.channels() + c];
unsigned char backgroundPx =
background.data[y * background.step + x * background.channels() + c];
output.data[y*output.step + output.channels()*x + c] =
backgroundPx * (1.-opacity) + foregroundPx * opacity;
}
}
}
}
FAST feature detector is faster than SURF and ORB.
Moreover, finding 1500 features in a 640*480 picture takes too much time. 300 features is ok. So you can use this code instead:
detail::OrbFeaturesFinder(Size(3,1),300));
Stitcher Class is so slow. I suggest you try to implement stitcher class yourself. Try using feature detectors, descriptors, then matching and after that find homography then making mask and then warping.
I don't understand your third question, "How can I catch directions between two images?". What do you mean exactly?

from float array to mat , concatenate blocks of image

I have an image 800x800 which is broken down to 16 blocks of 200x200.
(you can see previous post here)
These blocks are : vector<Mat> subImages;
I want to use float pointers on them , so I am doing :
float *pdata = (float*)( subImages[ idxSubImage ].data );
1) Now, I want to be able to get again the same images/blocks, going from float array to Mat data.
int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );
namedWindow( "Display window", WINDOW_AUTOSIZE );
for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
{
Mat mf( i,j, CV_32F, pdata + 200 );
imshow( "Display window", mf );
waitKey(0);
}
}
So , the problem is that I am receiving an
OpenCV Error: Assertion failed
in imshow.
2) How can I recombine all the blocks to obtain the original 800x800 image?
I tried something like:
int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );
Mat big( 800,800,CV_32F );
for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
{
Mat mf( i,j, CV_32F, pdata + 200 );
Rect roi(j,i,200,200);
mf.copyTo( big(roi) );
}
}
imwrite( "testing" , big );
This gives me :
OpenCV Error: Assertion failed (!fixedSize()) in release
in mf.copyTo( big(roi) );.
First, you need to know where are your subimages into the big image. To do this, you can save the rect of each subimage into the vector<Rect> smallImageRois;
Then you can use pointers (keep in mind that subimages are not continuous), or simply use copyTo to the correct place:
Have a look:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
resize(img, img, Size(800, 800));
Mat grayImg;
cvtColor(img, grayImg, COLOR_BGR2GRAY);
grayImg.convertTo(grayImg, CV_32F);
int N = 4;
if (((grayImg.rows % N) != 0) || ((grayImg.cols % N) != 0))
{
// Error
return -1;
}
Size graySize = grayImg.size();
Size smallSize(grayImg.cols / N, grayImg.rows / N);
vector<Mat> smallImages;
vector<Rect> smallImageRois;
for (int i = 0; i < graySize.height; i += smallSize.height)
{
for (int j = 0; j < graySize.width; j += smallSize.width)
{
Rect rect = Rect(j, i, smallSize.width, smallSize.height);
smallImages.push_back(grayImg(rect));
smallImageRois.push_back(rect);
}
}
// Option 1. Using pointer to subimage data.
Mat big1(800, 800, CV_32F);
int big1step = big1.step1();
float* pbig1 = big1.ptr<float>(0);
for (int idx = 0; idx < smallImages.size(); ++idx)
{
float* pdata = (float*)smallImages[idx].data;
int step = smallImages[idx].step1();
Rect roi = smallImageRois[idx];
for (int i = 0; i < smallSize.height; ++i)
{
for (int j = 0; j < smallSize.width; ++j)
{
pbig1[(roi.y + i) * big1step + (roi.x + j)] = pdata[i * step + j];
}
}
}
// Option 2. USing copyTo
Mat big2(800, 800, CV_32F);
for (int idx = 0; idx < smallImages.size(); ++idx)
{
smallImages[idx].copyTo(big2(smallImageRois[idx]));
}
return 0;
}
For concatenating the sub-images into a single squared image, you can use the following function:
// Important: all patches should have exactly the same size
Mat concatPatches(vector<Mat> &patches) {
assert(patches.size() > 0);
// make it square
const int patch_width = patches[0].cols;
const int patch_height = patches[0].rows;
const int patch_stride = ceil(sqrt(patches.size()));
Mat image = Mat::zeros(patch_stride * patch_height, patch_stride * patch_width, patches[0].type());
for (size_t i = 0, iend = patches.size(); i < iend; i++) {
Mat &patch = patches[i];
const int offset_x = (i % patch_stride) * patch_width;
const int offset_y = (i / patch_stride) * patch_height;
// copy the patch to the output image
patch.copyTo(image(Rect(offset_x, offset_y, patch_width, patch_height)));
}
return image;
}
It takes a vector of sub-images (or patches as I refer them to) and concatenates them into a squared image. Example usage:
vector<Mat> patches;
vector<Scalar> colours = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)};
// fill vector with circles of different colours
for(int i = 0; i < 16; i++) {
Mat patch = Mat::zeros(100,100, CV_32FC3);
circle(patch, Point(50,50), 40, colours[i % 3], -1);
patches.push_back(patch);
}
Mat img = concatPatches(patches);
imshow("img", img);
waitKey();
Will produce the following image
print the values of i and j before creating Mat mf and I believe you will soon be able to find the error.
Hint 1: i and j will be 0 the first time
Hint 2: Use the copyTo() with a ROI like:
cv::Rect roi(0,0,200,200);
src.copyTo(dst(roi))
Edit:
Hint 3: Try not to do such pointer fiddling, you will get in trouble. Especially if you're ignoring the step (like you seem to do).

Repeat an image without using bulit function for repeat image in OpenCV?

Basically here if we define a function i.e. repeat_image that takes three arguments in that function a matrix image and two integers nx, ny, and return a new image that is nxny times bigger, by repeating the image nxny times.
So if initial image was 640*480, repeat_image( img, 2, 2 ) will return an image of size 1280*960.
The arguments are:
- an matrix image (type Mat)
- an integer nx, the number of times the matrix should be repeated along the horizontal axis
- an integer ny, the number of times the matrix should be repeated along the vertical axis
You can repeat an image:
creating the destination image of the correct size
copying the source image with cv::copyTo in the correct ROI
Code:
#include <opencv2/opencv.hpp>
using namespace cv;
Mat image_repeat(const Mat& src, int nx, int ny)
{
Mat dst(src.rows * ny, src.cols * nx, src.type());
for (int iy = 0; iy < ny; ++iy)
{
for (int ix = 0; ix < nx; ++ix)
{
Rect roi(src.cols * ix, src.rows * iy, src.cols, src.rows);
src.copyTo(dst(roi));
}
}
return dst;
}
int main()
{
Mat3b img = imread("path_to_image");
Mat3b res = image_repeat(img, 4, 3);
imshow("img", img);
imshow("res", res);
waitKey();
return 0;
}
NOTES
this method works for any kind of input image
Mat image_repeat(Mat &img, int nx, int ny)
{
Mat img_repeat(Size(nx * img.cols, ny * img.rows), CV_8UC3);
int y = 0, x = 0;
while (y < ny)
{ //0<3
while (x < nx)
{ //0<2
for (int row = 0; row < img.rows; row++)
{
for (int col = 0; col < img.cols; col++)
{
img_repeat.at<Vec3b>(Point(col + (img.cols * x), row + (img.rows * y))) =img.at<Vec3b>(Point(col, row));
}
}
x++;
}
x = 0;
y++;
}
cout << "Image Repeat Done." << endl;
return img_repeat;
}

Showing image with changed pixel values openCV

I'm new to openCV and C++. I would like to change the pixel values of an image I loaded and display that new image in another window to compare the results (just visually). However, when I run the code, I get two original images. This means that either my for loop isn't doing what's it suppose to do (which i doubt since it makes sense to me) or the pixel value is lost and is not being saved to show the new image. I read a previous post that said I should include this statement after working with each pixel to set in to the altered image. The statement is: img.at(Point(x,y)) = color.
Could somebody please tell me what I'm doing wrong?
Thank you
cv::Mat img = cv::imread("12.jpg", CV_LOAD_IMAGE_COLOR);
// start of pixel navigation
Mat navigateImage(Mat) {
for(int x = 0; x > img.rows; x++)
{
for(int y = 0; y > img.cols; y++){
Vec3b color = img.at<Vec3b>(Point(x,y));
if ( color[0] > 10 && color [1] > 10 && color[2]> 10 )
{
color[0] = 0 ;
color[1] = 0;
color[2] = 0;
img.at<Vec3b>(Point(x,y)) = color;
}
else
{
color.val[0] = 255 ;
color.val[1] = 255;
color.val[2] = 255;
img.at<Vec3b>(Point(x,y)) = color;
}
}
}
return img;
}
// end of pixel navigation
int main( int argc, char** argv )
{
if(! img.data){
cout << "could not open or find the image" << endl;
return -1;}
Mat newImage = navigateImage(img);
cv::imshow( " Original", img);
cv::imshow( " Altered ", newImage);
cv::waitKey(0);
return 0;
}
(1). Firstly,
for(int x = 0; x > img.rows; x++)
and
for(int y = 0; y > img.cols; y++)
should be
for(int x = 0; x < img.cols; x++)
and
for(int y = 0; y < img.rows; y++)
respectively.
Since, you never enter the loop because of this mistake, both images are same.
(2). Secondly,
Mat navigateImage(Mat)
should be
Mat navigateImage(Mat img)
(3). Thirdly, put
cv::Mat img = cv::imread("12.jpg", CV_LOAD_IMAGE_COLOR);
in main function.
(4). Lastly,
replace,
Mat newImage = navigateImage();
by
Mat newImage = navigateImage(img.clone());
else, both images will be same.
CORRECTED CODE -
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
// start of pixel navigation
Mat navigateImage(Mat img) {
for(int x = 0; x < img.cols; x++)
{
for(int y = 0; y < img.rows; y++){
Vec3b color = img.at<Vec3b>(Point(x,y));
if ( color[0] > 10 && color [1] > 10 && color[2]> 10 )
{
color[0] = 0 ;
color[1] = 0;
color[2] = 0;
img.at<Vec3b>(Point(x,y)) = color;
}
else
{
color.val[0] = 255 ;
color.val[1] = 255;
color.val[2] = 255;
img.at<Vec3b>(Point(x,y)) = color;
}
}
}
return img;
}
// end of pixel navigation
int main( int argc, char** argv )
{
Mat img = cv::imread("12.png", CV_LOAD_IMAGE_COLOR);
if(! img.data){
cout << "could not open or find the image" << endl;
return -1;
}
Mat newImage = navigateImage(img.clone());
cv::imshow( " Original", img);
cv::imshow( " Altered ", newImage);
cv::waitKey(0);
return 0;
}