How to set pixel value of a cv::Mat1b? - c++

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

Related

Set transparency of pixel by it's value in cv::Mat

I have two cv::Mat objects, one is CV_8UC1 and it's loaded from grayscale QImage:
QImage tmp = QImage(path/to/image);
setMap(cv::Mat(tmp.height(),
tmp.width(),
CV_8UC1,
const_cast<uchar *>(tmp.bits()),
static_cast<size_t>(tmp.bytesPerLine())
));
After I load it, I want to get every pixel value and change transparency of that pixel by its value and convert it to QImage. Currently, I access pixels like this:
for(int i = 0; i < getMap().rows; i++)
{
for(int j = 0; j < getMap().cols; j++){
uchar v = getMap().at<uchar>(i,j);
//qDebug() << v;
}
}
Now, I think I have only one choice - convert it to CV_8UC4 (or copy it somehow) and change it's alpha value, but I don't know how to copy/convert it by pixel. As I said, I need to change it's transparency by it's grayscale value.
I tried this, but when I did, program crashed
getMap().convertTo(requestedMap_, CV_8UC4);
for(int i = 0; i < getMap().rows; i++)
{
for(int j = 0; j < getMap().cols; j++){
uchar v = getMap().at<uchar>(i,j);
if(v < 50)
requestedMap_.at<cv::Vec4i>(i,j)[3] = 0;
}
}
How can I solve it?
Thanks for your help!

Opencv only process the parts of image

I want to make a negative transformation for the image which is a very simple program.
But when I run the program. I want to transform all of the pixels in the image, but only 1/3 parts of that are processed. I don't make sure where is wrong. all the code I followed the book. But the result is different.
I think there is something wrong about the columns, but when I change the value of I.cols in negativeImage function with the actual value of image. the output still keep the same. only 1/3 parts of image are processed. If I 3 times the I.cols all of the pixels in the iamge could be processed.
vector<uchar> getNegativeLUT() {
vector<uchar> LUT(256, 0);
for (int i = 0; i < 256; ++i)
LUT[i] = (uchar)(255 - i);
return LUT;
}
void negativeImage(Mat& I) {
vector<uchar> LUT = getNegativeLUT();
for (int i = 0; i < I.rows; ++i) {
for (int j = 0; j < I.cols; ++j) {
I.at<uchar>(i, j) = LUT[I.at<uchar>(i, j)];
//stack overflow
}
}
}
int main() {
Mat image = imread("1.png");
Mat processed_image2 = image.clone();
negativeImage(processed_image2);
printf("%d", image.cols);
imshow("Input Image", image);
imshow("Negative Image", processed_image2);
waitKey(0);
return 0;
}
Output Image
You need to put correct type with at<> operator. Your PNG image has to be converted to 8UC1 to then use uchar type to access each pixel. I suppose your image has 3 channels, so you only iterate over 1/3 of the image. Also, I suggest you to use ptr<> operator in rows loop and then access to pixel as an array.
Mat M;
cvtColor(I, M, CV_BGR2GRAY);
// M is CV_8UC1 type
for(int i = 0; i < M.rows; i++)
{
uchar* p = M.ptr<uchar>(i);
for(int j = 0; j < I.cols; j++)
{
p[j] = LUT[p[j]];
}
}
EDIT: you should use cv::LUT instead of doing it yourself.
cv::Mat lut(1, 256, CV_8UC1);
for( int i = 0; i < 256; ++i)
{
lut.at<uchar>(0,i) = uchar(255-i);
}
cv::LUT(M, lut, result);

OpenCV GrabCut Mask

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>.

Convert RGB image in Mat to BYTE * in MFC

Sorry for putting it out here but opencv site is down or something i cannot access the topic there. I am reading a RGB image in Mat and than trying to convert in into BYTE* using the following function but it is not giving me the exact image but distorted part of some of the image. Please can anyone help me out here where i am mistaking it. Thank you.
BYTE *change_to_BYTE(Mat matrix_value)
{
BYTE* v_char_new = new BYTE[matrix_value.rows * matrix_value.cols * 3]();
vector<byte> v_char;
for(int i = 0; i < matrix_value.rows; i++)
{
for(int j = 0; j < matrix_value.cols; j++)
{
v_char_new[((i*matrix_value.cols+j) * 3)+0] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j + 0)));
v_char_new[((i*matrix_value.cols+j) * 3)+1] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j +1)));
v_char_new[((i*matrix_value.cols+j) * 3)+2] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j +2)));
}
}
return v_char_new;
}
After checking it out in different ways this was the one that worked for me.
BYTE *Ctest_face_projectDlg::change_to_BYTE(Mat matrix_value)
{
BYTE* v_char_new = new BYTE[matrix_value.rows * matrix_value.cols * 3]();
for(int i = 0; i < matrix_value.rows; i++)
{
for(int j = 0; j < matrix_value.cols; j++)
{
Vec3b bgrPixel = matrix_value.at<Vec3b>(i, j);
v_char_new[((i*matrix_value.cols+j)*3)+0] = bgrPixel.val[0];
v_char_new[((i*matrix_value.cols+j)*3)+1] = bgrPixel.val[1];
v_char_new[((i*matrix_value.cols+j)*3)+2] = bgrPixel.val[2];
// do something with BGR values...
}
}
}

How can I convert a Mat_ to Mat in the following code?

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;
...
}
}