I am trying to run kmeans on a 3 channel color image, but every time I try to run the function it seems to crash with the following error:
OpenCV Error: Assertion failed (data.dims <= 2 && type == CV_32F && K > 0) in unknown function, file ..\..\..\OpenCV-2.3.0\modules\core\src\matrix.cpp, line 2271
I've included the code below with some comments to help specify what is being passed in. Any help is greatly appreciated.
// Load in an image
// Depth: 8, Channels: 3
IplImage* iplImage = cvLoadImage("C:/TestImages/rainbox_box.jpg");
// Create a matrix to the image
cv::Mat mImage = cv::Mat(iplImage);
// Create a single channel image to create our labels needed
IplImage* iplLabels = cvCreateImage(cvGetSize(iplImage), iplImage->depth, 1);
// Convert the image to grayscale
cvCvtColor(iplImage, iplLabels, CV_RGB2GRAY);
// Create the matrix for the labels
cv::Mat mLabels = cv::Mat(iplLabels);
// Create the labels
int rows = mLabels.total();
int cols = 1;
cv::Mat list(rows, cols, mLabels .type());
uchar* src;
uchar* dest = list.ptr(0);
for(int i=0; i<mLabels.size().height; i++)
{
src = mLabels.ptr(i);
memcpy(dest, src, mLabels.step);
dest += mLabels.step;
}
list.convertTo(list, CV_32F);
// Run the algorithm
cv::Mat labellist(list.size(), CV_8UC1);
cv::Mat centers(6, 1, mImage.type());
cv::TermCriteria termcrit(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0);
kmeans(mImage, 6, labellist, termcrit, 3, cv::KMEANS_PP_CENTERS, centers);
The error says all: Assertion failed (data.dims <= 2 && type == CV_32F && K > 0)
These are very simple rules to understand, the function will work only if:
mImage.depth() is CV_32F
if mImage.dims is <= 2
and if K > 0. In this case, you define K as 6.
From what you stated on the question, it seems that:
IplImage* iplImage = cvLoadImage("C:/TestImages/rainbox_box.jpg");`
is loading the image as IPL_DEPTH_8U by default and not IPL_DEPTH_32F. This means that mImage is also IPL_DEPTH_8U, which is why your code is not working.
Related
I am learning image processing with OpenCV in C++. To implement a basic down-sampling algorithm I need to work on the pixel level -to remove rows and columns. However, when I assign values with mat.at<>(i,j) other values are assign - things like 1e-38.
Here is the code :
Mat src, dst;
src = imread("diw3.jpg", CV_32F);//src is a 479x359 grayscale image
//dst will contain src low-pass-filtered I checked by displaying it works fine
Mat kernel;
kernel = Mat::ones(3, 3, CV_32F) / (float)(9);
filter2D(src, dst, -1, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
// Now I try to remove half the rows/columns result is stored in downsampled
Mat downsampled = Mat::zeros(240, 180, CV_32F);
for (int i =0; i<downsampled.rows; i ++){
for (int j=0; j<downsampled.cols; j ++){
downsampled.at<uchar>(i,j) = dst.at<uchar>(2*i,2*j);
}
}
Since I read here OpenCV outputing odd pixel values that for cout I needed to cast, I wrote downsampled.at<uchar>(i,j) = (int) before dst.at<uchar> but it does not work also.
The second argument to cv::imread is cv::ImreadModes, so the line:
src = imread("diw3.jpg", CV_32F);
is not correct; it should probably be:
cv::Mat src_8u = imread("diw3.jpg", cv::IMREAD_GRAYSCALE);
src_8u.convertTo(src, CV_32FC1);
which will read the image as 8-bit grayscale image, and will convert it to floating point values.
The loop should look something like this:
Mat downsampled = Mat::zeros(240, 180, CV_32FC1);
for (int i = 0; i < downsampled.rows; i++) {
for (int j = 0; j < downsampled.cols; j++) {
downsampled.at<float>(i,j) = dst.at<float>(2*i,2*j);
}
}
note that the argument to cv::Mat::zeros is CV_32FC1 (1 channel, with 32-bit floating values), so Mat::at<float> method should be used.
I am trying to apply cartoon filter to a UIImage, with the help of OpenCV. My code is as the following
+ (UIImage *)createCartoonizedImageFromImage:(UIImage *)inputImage {
int num_down = 2; //number of downsampling steps
cv::Mat image_rgb = [self cvMatFromUIImage:inputImage];
cv::Mat image_color;
cv::cvtColor(image_rgb, image_color, cv::COLOR_RGBA2RGB);
//downsample image using Gaussian pyramid
for(int i = 0; i < num_down; i++)
{
cv::pyrDown(image_color, image_color);
}
// apply bilateral filter
cv::Mat image_bilateral = image_color.clone();
cv::bilateralFilter(image_color, image_bilateral, 9, 9, 7);
// upsample image to original size
for(int i = 0; i < num_down; i++)
{
cv::pyrUp(image_color, image_color);
}
// convert to grayscale
cv::Mat image_gray;
cv::cvtColor(image_rgb, image_gray, cv::COLOR_RGB2GRAY);
// apply median blur
cv::Mat image_blur;
cv::medianBlur(image_gray, image_blur, 7);
// detect and enhance edges
cv::Mat image_edge;
cv::adaptiveThreshold(image_blur, image_edge, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 9, 2);
// convert back to color, bit-AND with color image
cv::cvtColor(image_edge, image_edge, cv::COLOR_GRAY2RGB);
cv::Mat image_cartoon;
cv::bitwise_and(image_bilateral, image_edge, image_cartoon);
UIImage *cartoonImage = [self UIImageFromCVMat:image_cartoon];
return cartoonImage;
}
on the line
cv::bitwise_and(image_bilateral, image_edge, image_cartoon);
the above code gives me a following error
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array') in binary_op, file /Users/kyle/code/opensource/opencv/modules/core/src/arithm.cpp, line 225
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /Users/kyle/code/opensource/opencv/modules/core/src/arithm.cpp:225: error: (-209) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function binary_op
My Question
I know that the problem is with the incorrect sizes of input arrays. but how can i correct them and make them of the same size without effecting the end result ?
As clearly Stated in the OpenCV Error: "Sizes of input arguments do not match". i.e image_bilateral.size != image_edge.size(). A simple debug print will do the trick! So next time try to use your debugger! Here is your modified code!
int num_down = 2; //number of downsampling steps
cv::Mat image_rgb = imread(FileName1,1);
cv::Mat image_color;
cv::cvtColor(image_rgb, image_color, cv::COLOR_RGBA2RGB);
//downsample image using Gaussian pyramid
for(int i = 0; i < num_down; i++)
{
cv::pyrDown(image_color, image_color);
}
// apply bilateral filter
cv::Mat image_bilateral = image_color.clone();
cv::bilateralFilter(image_color, image_bilateral, 9, 9, 7);
// upsample image to original size
for(int i = 0; i < num_down; i++)
{
cv::pyrUp(image_color, image_color);
cv::pyrUp(image_bilateral, image_bilateral);//Bug <-- Here Missing to Resize the bilateralFilter image?
}
// convert to grayscale
cv::Mat image_gray;
//cv::cvtColor(image_rgb, image_gray, cv::COLOR_RGB2GRAY);//Bug <-- Using RGBA instead of RGB
cv::cvtColor(image_color, image_gray, cv::COLOR_RGB2GRAY);
// apply median blur
cv::Mat image_blur;
cv::medianBlur(image_gray, image_blur, 7);
// detect and enhance edges
cv::Mat image_edge;
cv::adaptiveThreshold(image_blur, image_edge, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 9, 2);
// convert back to color, bit-AND with color image
cv::cvtColor(image_edge, image_edge, cv::COLOR_GRAY2RGB);
cv::Mat image_cartoon;
//cv::bitwise_and(image_bilateral, image_edge, image_cartoon);//Bug <-- Here Size of image_bilateral is 1/4 of the image_edge
cv::bitwise_and(image_bilateral, image_edge, image_cartoon);
imshow("Cartoon ",image_cartoon);
My kmeans() function is failing with the error:
OpenCV Error: Assertion failed (N >= K) in cv::kmeans, file C:\builds\master_Pac
kSlave-win32-vc12-shared\opencv\modules\core\src\kmeans.cpp, line 231
Whats my error? 'N >= K' must mean its checking whether the Mat rows*cols(length) is > clusters - which mine is (I think). My Mat has 1 row with around 80k columns. Is my Mat that I am passing as the first parameter (for kmeans) empty of pixel/voxel data? I have confirmed that this parameter is a 'collapsed' image (1 row, 80K columns). So its not quite empty but it could all that it's all black pixels which may be the error?
Mat image = imread("images/jp.png", CV_32F); // The Jurassic Park movie logo
cvtColor(image, image, CV_BGR2RGB);
Mat collapsedImage = image.reshape(1, 1);
collapsedImage.convertTo(collapsedImage, CV_32F);
int clusterCount = 2;
Mat labels, centres;
// Assertion error thrown here
kmeans(collapsedImage, clusterCount, labels,
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0),
3, KMEANS_PP_CENTERS, centres);
imshow("flat", collapsedImage); // shows long flat with all black pixels
imshow("image", image);
Ok looks like the problem was my reshaping. It should be:
Mat collapsedImage = image.reshape(1, image.rows * image.cols);
I was trying to write Point2f imagePoints to a Mat image in openCV. I was following the link below.
Create Mat from vector<point2f>
But I am getting 'Assertion failed' error. Please help.
Code:
std::vector<cv::Point3d> objectPoints;
std::vector<cv::Point2d> imagePoints;
cv::Mat intrisicMat(3, 3, cv::DataType<double>::type);
intrisicMat.at<double>(0, 0) = param.focalLength.first;
intrisicMat.at<double>(0, 1) = 0;
intrisicMat.at<double>(0, 2) = param.principalPoint.first;
intrisicMat.at<double>(1, 0) = 0;
intrisicMat.at<double>(1, 1) = param.focalLength.second;
intrisicMat.at<double>(1, 2) = param.principalPoint.second;
intrisicMat.at<double>(2, 0) = 0;
intrisicMat.at<double>(2, 1) = 0;
intrisicMat.at<double>(2, 2) = 1;
cv::Mat rVec(3, 1, cv::DataType<double>::type); // Rotation vector
rVec.at<double>(0) = 0;
rVec.at<double>(1) = 0;
rVec.at<double>(2) = 0;
cv::Mat tVec(3, 1, cv::DataType<double>::type); // Translation vector
tVec.at<double>(0) = 0;
tVec.at<double>(1) = 0;
tVec.at<double>(2) = 0;
cv::Mat distCoeffs(5, 1, cv::DataType<double>::type); // Distortion vector
distCoeffs.at<double>(0) = param.distortionRadial.at(0);
distCoeffs.at<double>(1) = param.distortionRadial.at(1);
distCoeffs.at<double>(2) = param.distortionTangential.first;
distCoeffs.at<double>(3) = param.distortionTangential.second;
distCoeffs.at<double>(4) = param.distortionRadial.at(2);
projectPoints(objectPoints, rVec, tVec, intrisicMat, distCoeffs, imagePoints);
Mat depthImage = Mat(imagePoints);
imwrite("E:/softwares/1.8.0.71/bin/depthImage.jpg", depthImage);
cout << "depthImage.channels()=" << depthImage.channels() << endl;
Error:
OpenCV Error: Assertion failed (image.channels() == 1 || image.channels() == 3 || image.channels() == 4) in cv::imwrite_, file E:\softwares\opencv-3.1.0\opencv-3.1.0\modules\imgcodecs\src\loadsave.cpp, line 455
My image has 2 channels. So ImWrite() is throwing assertion failed error. How can I create a Mat image using the Image points if not like this?
With what you have written in the comments, it seems that you're trying to imwrite your Mat to a file. The problem is, a Mat from Vector<Point2f> will give a 2 channels matrix, which is not compatible with any image format (grayscale, RGB or RGBA).
Moreover, please edit your main post to show the code (using markdown) so it is easier to read and then help you.
I am trying to copy one image to another pixel by pixel (I know there are sophisticated methods available. I am trying to solve another problem and answer to this will be useful).
This is my code:
int main()
{
Mat Img;
Img = imread("../../../stereo_images/left01.jpg");
Mat copyImg = Mat::zeros(Img.size(), CV_8U);
for(int i=0; i<Img.rows; i++){
for(int j=0; j<Img.cols; j++){
copyImg.at<uchar>(j,i) = Img.at<uchar>(j,i);
}}
namedWindow("Image", CV_WINDOW_AUTOSIZE );
imshow("Image", Img);
namedWindow("copyImage", CV_WINDOW_AUTOSIZE );
imshow("copyImage", copyImg);
waitKey(0);
return 0;
}
When I run this code in visual studio I get the following error
OpenCV Error: Assertion failed (dims <= 2 && data && (unsigned)i0 < (unsigned)si
ze.p[0] && (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channel
s()) && ((((sizeof(size_t)<<28)|0x8442211) >> ((DataType<_Tp>::depth) & ((1 << 3
) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file c:\opencv\opencv-2.4.9\ope
ncv\build\include\opencv2\core\mat.hpp, line 537
I know for fact that Img's type is CV_8U. Why does this happen ?
Thanks!
// will read in a rgb image , no matter what the content is
Img = imread("../../../stereo_images/left01.jpg");
to make it read grayscale images use:
Img = imread("../../../stereo_images/left01.jpg", CV_LOAD_IMAGE_GRAYSCALE);
then, you don't need to copy per pixel (and you should even avoid that), just use:
Mat im2 = Img.clone();
if you do per-pixel loops, watch out to get the indices right. it's row-col world here, not x,y, so it should be:
copyImg.at<uchar>(i,j) = Img.at<uchar>(i,j);
in your case
I know for fact that Img's type is CV_8U.
But CV_8U is just the image depth (8-bit U-nsigned). The type also specifies the number of channels, which is usually three. One for blue, one for green and one for red in this order as default for OpenCV. The type would be CV_8UC3 (C-hannels = 3). imread will convert even a black and white image to a 3-channel image by default. imread(filename, CV_LOAD_IMAGE_GRAYSCALE) will load a 1-channel image (CV_8UC1). But if you're not sure the easiest solution is
Mat copyImg = Mat::zeros(Img.size(), Img.type());
To access the array elements you have to know the size of it. Using .at<uchar>() on a 3-channel image will only access the first channel because you have 3*8 bit per pixel. So on a 3-channel image you have to use
copyImg.at<Vec3b>(i,j) = Img.at<Vec3b>(i,j);
where Vec3b is a cv::Vec<uchar, 3>. You should also note that the first argument of at<>(,) is the index along dim 0 which are the rows and second argument cols. Or in other words in classic 2d-xy-chart order you access a pixel with .at<>(y,x) == .at<>(Point(x,y)).
your problem is with this line :
copyImg.at<uchar>(j,i) = Img.at<uchar>(j,i);
It should be :
copyImg.at<uchar>(i,j) = Img.at<uchar>(i,j);
Note that if you want to copy image you can simply do this :
Mat copyImg = Img.clone();