Mat m1 = Mat(500, 300, CV_64F, Vec3b(255,255,255));
for (int i = 0; i < m1.rows; ++i)
for (int j = 0; j < m1.cols; ++j)
{
Vec3b color=m1.at<Vec3b>(Point(i, j));
}
imshow("test2", m1);
waitKey();
The variable color should contain the color of the pixel which is white but i when i run the code i get the error:
OpenCV Error: Assertion failed (((((sizeof(size_t)<<28)|0x8442211) >>
((traits::Depth<_Tp>::value) & ((1 << 3) - 1))*4) & 15) ==
elemSize1()) in cv::Mat::at, file
c:\opencv\build\include\opencv2\core\mat.inl.hpp, line 1118
The error message is telling you what you need to know. You've gone out of bounds!
Try:
Point(j, i)
Columns correspond to x. Rows correspond to y.
try this
Mat m1 = Mat(500, 300, CV_64F, Vec3b(255,255,255));
for (int i = 0; i < m1.rows; ++i)
for (int j = 0; j < m1.cols; ++j)
{
Vec3b color=m1.at<Vec3b>(i, j);//changed
}
imshow("test2", m1);
waitKey();
Related
I have utilised the OpenCV GrabCut functionality to perform an image segmentation. When viewing the segmented image as per the code below, the segmentation is reasonable/correct. However, when looking at(at attempting to use) the segmrntation mask values, I am getting some very large numbers, and not the enumerated values one would expect from the cv::GrabCutClasses enum.
void doGrabCut(){
Vector2i imgDims = getImageDims();
//Wite image to OpenCV Mat.
const Vector4u *rgb = getRGB();
cv::Mat rgbMat(imgDims.height, imgDims.width, CV_8UC3);
for (int i = 0; i < imgDims.height; i++) {
for (int j = 0; j < imgDims.width; j++) {
int idx = i * imgDims.width + j;
rgbMat.ptr<cv::Vec3b>(i)[j][2] = rgb[idx].x;
rgbMat.ptr<cv::Vec3b>(i)[j][1] = rgb[idx].y;
rgbMat.ptr<cv::Vec3b>(i)[j][0] = rgb[idx].z;
}
}
//Do graph cut.
cv::Mat res, fgModel, bgModel;
cv::Rect bb(bb_begin.x, bb_begin.y, bb_end.x - bb_begin.x, bb_end.y - bb_begin.y);
cv::grabCut(rgbMat, res, bb, bgModel, fgModel, 10, cv::GC_INIT_WITH_RECT);
cv::compare(res, cv::GC_PR_FGD, res, cv::CMP_EQ);
//Write mask.
Vector4u *maskPtr = getMask();//uchar
for (int i = 0; i < imgDims.height; i++) {
for (int j = 0; j < imgDims.width; j++) {
cv::GrabCutClasses classification = res.at<cv::GrabCutClasses>(i, j);
int idx = i * imgDims.width + j;
std::cout << classification << std::endl;//Strange numbers here.
maskPtr[idx].x = (classification == cv::GC_PR_FGD) ? 255 : 0;//This always evaluates to 0.
}
}
cv::Mat foreground(rgbMat.size(), CV_8UC3, cv::Scalar(255, 255, 255));
rgbMat.copyTo(foreground, res);
cv::imshow("GC Output", foreground);
}
Why would one get numbers outside the enumeration when the segmentation is qualitatively correct?
I doubt on your //Write mask. step, why do you re-iterate the res and modify maskPtr as maskPtr[idx].x = (classification == cv::GC_PR_FGD) ? 255 : 0;, Basically you already have a single channel Binary image stored in the res variable, the cv::compare() returns a binary image
However if you still want to debug the values by iteration then you should use the standard technique for iterating a single channel image as:
for (int i = 0; i < m.rows; i++) {
for (int j = 0; j < m.cols; j++) {
uchar classification = res.at<uchar>(i, j);
std::cout << int(classification) << ", ";
}
}
As you are iterating a single channel mat you must use res.at<uchar>(i, j) and not res.at<cv::GrabCutClasses>.
I have two gray scale images, and I want to copy the histogram of one image to the other. Since I'm working with OpenCv, I've tried both this method histogram recoloring and this histogram for gray scale images. The first link gives me no results, while the second return this image:
Reference Image:
Input Image:
Result Image:
According to the code of the grayscale histogram matching, I had to implement the cumsum and ScanImageAndReduceC function:
cumsum:
for (size_t i = 0; i < X.rows; i++)
{
for (size_t j = 0; j < X.cols; j++)
{
if (j == 0)
{
result.at<double>(i, j) = X.at<double>(i, j);
}
else
{
result.at<double>(i, j) = X.at<double>(i, j) + result.at<double>(i, j - 1);
}
}
}
while the other functin was picked from here: how to scan images.
How can I succesfully copy the histogram of one image to another?
I'm using OpenCV 3.1
Thank!
I'm also trying to solve the problem,and I find the bug in your function "cumsum".The function of "cumsum" should be written as :
Mat cumsum (Mat & src)
{
Mat result = Mat::zeros(Size(src.cols,src.rows),CV_32FC1);
for (int i = 0; i < src.rows; ++i)
{
for (int j = 0; j < src.cols; ++j)
{
if (i == 0)
{
result.at<float>(i, j) = src.at<float>(i, j);
}
else
{
result.at<float>(i, j) = src.at<float>(i, j) + result.at<float>(i-1, j);
}
}
}
return result;
}
I have copied a grayscale image into a cv::Mat1b, and I want to loop through each pixel and read and change its value. How can I do that?
My code looks like this :
cv::Mat1b newImg;
grayImg.copyTo(newImg);
for (int i = 0; i < grayImg.rows; i++) {
for (int j = 0; i < grayImg.cols; j++) {
int pixelValue = static_cast<int>(newImg.at<uchar>(i, j));
if(pixelValue > thresh)
newImg.at<int>(i,j) = 0;
else
newImg.at<int>(i, j) = 255;
}
}
But in the assignments (inside of if and else), I get the error Access violation writing location.
How do I read and write specific pixels correctly?
Thanks !
Edit
Thanks to #Miki and #Micka, this is how I solved it :
for (int i = 0; i < newImg.rows; i++) {
for (int j = 0; j < newImg.cols; j++) {
// read :
cv::Scalar intensity1 = newImg.at<uchar>(i,j);
int intensity = intensity1.val[0];
// write :
newImg(i, j) = 255;
}
}
newImg.at<int>(i,j)
should be
newImg.at<uchar>(i,j)
Because cv::Mat1b is of uchar type
i suggest :
cv::Mat1b newImg;
newImg = grayImg > thresh ;
or
cv::Mat1b newImg;
newImg = grayImg < thresh ;
also look at the OpenCV Tutorials to know how to go through each and every pixel of an image
below is a snippet from the opencv SVM tutorial at this link. And in that snippet is this line of code ' Mat sampleMat = (Mat_(1,2) << j,i);'. Instead of using the Mat_ template, I would need to use a regular Mat object. I was hoping someone can show me how to convert the Mat_ to a Mat in the previous line.
I tried Mat sampleMat = (Mat(1,2, CV_32FC1) << j,i); //but get a long page of errors
I tried Mat sampleMat = Mat(1,2, CV_32FC1) << j,i; //same, long page of errors
I just need the code at the link at the top of the page to run without using the Mat_ and only use a Mat in its place...if someone can show me how to write that line I'd appreciate it.
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << j,i);
float response = SVM.predict(sampleMat);
if (response == 1)
image.at<Vec3b>(i,j) = green;
else if (response == -1)
image.at<Vec3b>(i,j) = blue;
}
Edit: Trying to run like below but getting errors
Vec3b green(0,255,0), blue (255,0,0);
// Show the decision regions given by the SVM
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat(1, 2, CV_32F);
float * const pmat = sampleMat.ptr<float>();
pmat[0] = i;
pmat[1] = j;
float response = SVM.predict(sampleMat);
if (response == 1)
pmat[0] = green;
pmat[1] = green;
else if (response == -1)
pmat[0] = blue;
pmat[1] = blue;
}
I figured you'd know enough so I didn't need the errors=)
Set the values directly:
Mat sampleMat(1, 2, CV_32F);
sampleMat.at<float>(0,1) = j;
sampleMat.at<float>(0,2) = i;
or
Mat sampleMat(1, 2, CV_32F);
float * const pmat = sampleMat.ptr<float>();
pmat[0] = j;
pmat[1] = i;
Addendum:
Seeing your loop, you could make it a bit more efficient in the case that SVM.predict doesn't modify sampleMat. You can set the image row just once per row, instead of doing it all the time:
for (int i = 0; i < image.rows; ++i)
{
Mat sampleMat(1, 2, CV_32F);
sampleMat.at<float>(0, 2) = i;
for (int j = 0; j < image.cols; ++j)
{
sampleMat.at<float>(0, 1) = j;
...
}
}
I'm trying to get the number of difference between two pictures.
When I compare 2 images in gray scale, pixDiff <> 0 but when it come to RGB, pixDiff is always 0.
I used openCV's compare and also a custom loop.
Mat frame, oldFrame;
cap >> oldFrame;
if(analyseMod == MONOCHROME)
cvtColor(oldFrame, oldFrame, CV_BGR2GRAY);
nbChannels = oldFrame.channels();
while(1)
{
pixDiff = 0;
cap >> frame;
//Test diff
Mat diff;
compare(oldFrame, frame, diff, CMP_NE);
imshow("video 0", diff);
imshow("video 1", frame);
if(analyseMod == MONOCHROME)
{
cvtColor(frame, frame, CV_BGR2GRAY);
for(int i=0; i<frame.rows; i++)
for(int j=0; j<frame.cols; j++)
if(frame.at<uchar>(i,j) < oldFrame.at<uchar>(i,j) - similarPixelTolerance || frame.at<uchar>(i,j) > oldFrame.at<uchar>(i,j) + similarPixelTolerance)
pixDiff++;
}
else if(analyseMod == RGB)
{
uint8_t *f = (uint8_t *)frame.data;
uint8_t *o = (uint8_t *)oldFrame.data;
for(int i=0; i<frame.rows; i++)
{
for(int j=0; j<frame.cols; j++)
{
if(f[nbChannels*i*frame.cols + j + RED] < o[nbChannels*i*oldFrame.cols + j + RED])
pixDiff++;
}
}
}
frame.copyTo(oldFrame);
cout << pixDiff;
if(waitKey(30) >= 0) break;
}
Thx for help
I still don't get it, why are you not using your delta in the RGB case, but here is the solution for both cases, if you want to consider color channels separately. Set CN to 1 for monochrome case and to 3 for RGB case.
const int CN = 3; // 3 for RGB, 1 for monochrome
uint8_t *f = frame.ptr<uint8_t>();
uint8_t *o = oldFrame.ptr<uint8_t>();
for(int i = 0; i < frame.rows; ++i)
{
for(int j = 0; j < frame.cols; ++j)
{
for (int c = 0; c < CN; ++c)
{
if (abs(*f - *o) > similarPixelTolerance) ++pxDiff;
++f, ++o;
}
}
}
It is way more efficient to access pixels in this way than to call at for each pixel. The only possible problem is if you have some padding in your images, but by default OpenCV is using continuous allocation.