Convert RGB image in Mat to BYTE * in MFC - c++

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

Related

Subtract opencv matrix from 3 channel matrix

I have two matrices:
cv::Mat bgr(rows, cols, CV_16UC3);
cv::Mat ir(rows, cols, CV_16UC1 );
and I want to subtract ir from each channel of bgr element-wise. I couldn't find an elegant solution yet.
EDIT
One possible solution might be:
// subtract IR from BGR
Vec3u tmp;
for (int i = 0; i < ir.rows; i++) {
for (int j = 0; j < ir.cols; j++) {
tmp = bgr.at<Vec3u>(i,j);
tmp[0] = tmp[0] - ir.at<ushort>(i,j);
tmp[1] = tmp[1] - ir.at<ushort>(i,j);
tmp[2] = tmp[2] - ir.at<ushort>(i,j);
bgr.at<Vec3u>(i, j) = tmp;
}
}
The question is that whether there is a faster solution.
If we're talking about an elegant way, it could be like this:
Mat mat = Mat::ones(2,2,CV_8UC1);
Mat mat1 = Mat::ones(2,2,CV_8UC2)*3;
Mat mats[2];
split(mat1,mats);
mats[0]-=mat;
mats[1]-=mat;
merge(mats,2,mat1);
You shouldn't use at(), if you wanted your code to be more efficient. Use pointers and check Mats for continuity:
int rows = mat.rows;
int cols = mat.cols;
if(mat.isContinuous() && mat1.isContinuous())
{
cols*=rows;
rows = 1;
}
for(int j = 0;j<rows;j++) {
auto channe2limg = mat1.ptr<Vec2b>(j);
auto channelimg = mat.ptr<uchar>(j);
for (int i = 0; i < cols; i++) {
channe2limg[i][0]-=channelimg[i];
channe2limg[i][1]-=channelimg[i];
}
}

Issues in Multiplying two RGB images in opencv using c++

I want to multiply one image by its transpose. my image size is nxm.
i do as follows
for (int k = 0; k < total_images; k++)
{
Mat img_tp1 = cv::Mat(imgRows, imgCols, CV_32FC1);
Mat img_tp2 = cv::Mat(imgRows, imgRows, CV_32FC1);
subtract(img[k], MeanMat, img_tp1);
img_tp2 = img_tp1 * img_tp2.t();
std::ostringstream name;
name << "sub" << k << ".jpg";
cv::imwrite(name.str(), img_tp2);
}
and i face this error
Unhandled exception at 0x000007FEFDB79E5D in Tracking.exe: Microsoft C++ exception: cv::Exception at memory location 0x00000000001E5EE0.
how can i do this multiplication? in fact i want to compute the covariance matrix of the sequence of images so i need this multiplication.
Thanks.
Then i decide to implement the multiplying for my RGB image and i use this code:
for (int i = 0; i < imgRows; i++)
{
for (int j = 0; j < imgRows; j++)
{
uchar pix1[3];
uchar pix2[3];
uchar pix[3] = { 0, 0, 0 };
for (int k = 0; k < imgCols; k++)
{
img_tp1.at<Vec3b>(i, k) = { pix1[0], pix1[1], pix1[2] };
img_tp1.at<Vec3b>(j, k) = { pix2[0], pix2[1], pix2[2] };
CovMat0.at<Vec3b>(i, j) = { pix[0], pix[1], pix[2] };
pix[0] = (pix1[0] * pix2[0]) + pix[0];
pix[1] = (pix1[1] * pix2[1]) + pix[1];
pix[2] = (pix1[2] * pix2[2]) + pix[2];
CovMat0.at<Vec3b>(i, j) = { pix[0], pix[1], pix[2] };
}
}
}
but it takes lots of time to process it. Is there any better way for that?
(I want to multiply one image by its transpose)

How to set pixel value of a cv::Mat1b?

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

Array index seems to slide when writing values

I have a Npp8u * image = new Npp8u[nWidth * nHeight]; array that stores grayscale image values. I defined Npp8u as typedef unsigned char Npp8u;. The problem occurs when I try to subtract the lowest image value from ever pixel.
I use this function to do the subtraction.
void SubtractValue(Npp8u * image, int width, int height, Npp8u value){
int iValue = value;
for (int i = 0; i < height; ++i){
for (int j = 0; j < width; ++j){
int indexVal = (image[i*width + j]);
int newVal = indexVal - iValue;
image[i*width + j] = (Npp8u) newVal;
}
}
}
Result of this function is quite strange. I use Lena Image to test, this is the original image.
If the value is 85 I get the following image
Note: The original image is .pgm
Reading procedure:
for (int i = 0; i < nHeight; ++i)
for (int j = 0; j < nWidth; ++j)
image[i*nWidth + j] = fgetc(fInput);
Writing procedure:
for (int i = 0; i < nHeight; ++i)
for (int j = 0; j < nWidth; ++j)
fputc(image[i*nWidth + j], fOutput);
Update: The problem occurs if the pixel has the value 10, which is new line feed.
Since you mentioned that character 10 was causing the issue, one would suspect that the image format you're reading/writing needs to processed in "binary" file mode, so that ASCII 10 is not treated as a line feed.
Therefore make sure that file is opened in binary mode (for fopen use the "rb" or "wb" flags, depending on whether you're reading or writing).

OpenCV get pixel channel value from Mat image

Maybe I'm not looking hard enough, but everything seems to want me to use an array. Thus, how do I get the channel value for a particular pixel for foo if foo is something like Mat foo = imread("bar.png")?
Assuming the type is CV_8UC3 you would do this:
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
Vec3b bgrPixel = foo.at<Vec3b>(i, j);
// do something with BGR values...
}
}
Here is the documentation for Vec3b. Also, don't forget OpenCV stores things internally as BGR not RGB.
EDIT :
For performance reasons, you may want to use direct access to the data buffer in order to process the pixel values:
Here is how you might go about this:
uint8_t* pixelPtr = (uint8_t*)foo.data;
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = pixelPtr[i*foo.cols*cn + j*cn + 0]; // B
bgrPixel.val[1] = pixelPtr[i*foo.cols*cn + j*cn + 1]; // G
bgrPixel.val[2] = pixelPtr[i*foo.cols*cn + j*cn + 2]; // R
// do something with BGR values...
}
}
Or alternatively:
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
uint8_t* rowPtr = foo.row(i);
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = rowPtr[j*cn + 0]; // B
bgrPixel.val[1] = rowPtr[j*cn + 1]; // G
bgrPixel.val[2] = rowPtr[j*cn + 2]; // R
// do something with BGR values...
}
}
The below code works for me, for both accessing and changing a pixel value.
For accessing pixel's channel value :
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
uchar col = intensity.val[k];
}
}
}
For changing a pixel value of a channel :
uchar pixValue;
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b &intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
// calculate pixValue
intensity.val[k] = pixValue;
}
}
}
`
Source : Accessing pixel value
The pixels array is stored in the "data" attribute of cv::Mat. Let's suppose that we have a Mat matrix where each pixel has 3 bytes (CV_8UC3).
For this example, let's draw a RED pixel at position 100x50.
Mat foo;
int x=100, y=50;
Solution 1:
Create a macro function that obtains the pixel from the array.
#define PIXEL(frame, W, x, y) (frame+(y)*3*(W)+(x)*3)
//...
unsigned char * p = PIXEL(foo.data, foo.rols, x, y);
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R
Solution 2:
Get's the pixel using the method ptr.
unsigned char * p = foo.ptr(y, x); // Y first, X after
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R