Loading an array of pixel values in OpenCV - c++

I have a 32-bit integer array containing pixel values of a 3450x3450 image I want to create a Mat image with. Tried the following:
int *image_array;
image_array = (int *)malloc( 3450*3450*sizeof(int) );
memset( (char *)image_array, 0, sizeof(int)*3450*3450 );
image_array[0] = intensity_of_first_pixel;
...
image_array[11902499] = intensity_of_last_pixel;
Mat M(3450, 3450, CV_32FC1, image_array);
and upon displaying the image I get a black screen. I should also note the array contains a 16-bit grayscale image.

I guess you should try to convert the input image, which I assume is in RGB[A] format using:
cv::Mat m(3450, 3450, CV_8UC1, image_array) // For GRAY image
cv::Mat m(3450, 3450, CV_8UC3, image_array) // For RGB image
cv::Mat m(3450, 3450, CV_8UC4, image_array) // For RGBA image

Related

Creating a cv::Mat image from a 3d array

Suppose I have an array
uint8_t img[1000][1200][3]
where the first 2 dimensions represent the size of the image (height, width),
and the third one the channels (BGR).
E.g.
img[200][100][1]
gives the value of the Green pixel with coordinates (200, 100).
How can I convert this array to a cv::Mat image?
I tried
cv::Mat my_image(1000, 1200, CV_8UC3, img);
but I am not sure if the result I am getting is correct. Any hints?
Not an expert in cpp, but the idea is following:
uint8_t img[1000][1200][3];
uint8_t *p = img;
//Consturctor takes a pointer to image data, possibly you will need to swap height and width.
cv::Mat my_image(1000, 1200 CV_8UC3, (void*)p);

cv::imshow will not recognize an interleaved pointer wrapped in a cv::Mat

I have two functions that pass images using pointers
funct 1: Read a gray image from file, do image processing. Convert the processed image to color (3-channel). Wrapping it in a pointer.
funct 2: have an image pointer as input. Wrap it in a cv mat and show it. Do some other things.
funct 1:
cv::Mat imIn = cv::Mat(height, width,CV_16UC1);
cv::Mat outImage;
// read image
std::ifstream ifs{ imagesPathVec, std::ios::in | std::ios::binary };
if ( ifs.is_open() )
{
ifs.read( reinterpret_cast<char *>( imIn.data ), imIn.total() * imIn.elemSize() );
ifs.close();
}
imIn.convertTo(outImage, CV_32F);
//... some image processing applied to outImage
outImage.convertTo(outImage, CV_8UC1);
//wrapping the pointer outStreamBuffer in a cv::Mat.
cv::Mat outStream(height, width, CV_8UC3, static_cast<uint8_t*>(*outStreamBuffer));
// Try two methods to convert to color images.
//Method 1.
std::vector<cv::Mat> images(3);
images.at(0) = outImage;
images.at(1) = outImage;
images.at(2) = outImage;
cv::merge(images, outStream);
//Method 2.
cv::cvtColor(outImage, outStream, CV_GRAY2RGB);
Function 2
//wrap the incomming pointer inStreamBuffer in a Mat
cv::Mat inImage = cv::Mat(height, width, CV_8UC3, static_cast<uint8_t*>(*inStreamBuffer), width*3);
cv::imshow("m_inImage ", inImage);
cv::waitKey(10);
Since it is a gray image with 3 channels. I try to convert it to color by calling cvtColor() before the call to cv::imshow()
cv::cvtColor(inImage, inImage,CV_RGB2BGR);
but the results were the same.
The displayed image is
I would appreciate if you can help me to show the image correctly. Also help me to underestand what it is going on. Why opencv is not recognizing its own interleaved image?

Opencv - Create Mat from array

I try to create mat object from uchar* . I could not find a useful conversion. My code is below ;
uchar* urgbImg; // this value is created another function
Mat img_argb(HEIGHT, WIDTH, CV_8UC4, urgbImg);
Mat img_rgb(HEIGHT, WIDTH, CV_8UC3);
img_argb.convertTo(img_rgb, CV_8UC3);
cv::imwrite("RGB.png", img_rgb);
QImage img1(urgbImg, WIDTH, HEIGHT, QImage::Format_ARGB32);
QImage img2 = img1.convertToFormat(QImage::Format_RGB32);
QFile file2(QString::fromStdString("QRGB.png"));
file2.open(QIODevice::WriteOnly);
img2.save(&file2,"PNG",100);
file2.close();
QRGB file is a fine result but not RGB file. I have uchar array so it is 8 bit.
I tried CV_8UC3(without conversion from CV_8UC4), CV_32SC3 and CV_32SC4. All result are bad. How can I create rgb image from uchar* ?
convertTo() don't convert a CV_8UC4 image to CV_8UC3
you should use cvtColor() function
Mat img_argb(HEIGHT, WIDTH, CV_8UC4, urgbImg);
Mat img_rgb;
cvtColor(img_argb,img_rgb,COLOR_BGRA2BGR);

Add alpha channel to opencv Mat

Using the cv::imread I was able to reading the RGB image to cv::Mat (as below)
Mat picture = imread(fileName, -1);
Instead of reading, I tried to create an RGB image using the following code :
Mat arr1 = Mat(9, 9, CV_8UC1, &data1);
Mat arr2 = Mat(9, 9, CV_8UC1, &data2);
Mat arr3 = Mat(9, 9, CV_8UC1, &data3);
Mat pic;
vector<Mat> mk(3);
mk.at(0)=(arr1);
mk.at(1)=(arr2);
mk.at(2)=(arr3);
merge(mk,pic);
Will the Mat picture and Mat pic be equal?
As cv::imread has a flag of '-1' which indicates that 'Return the loaded image as is (with alpha channel)'. Which I am not able to understand and how do I match 'pic' to 'picture'?(Not picture to pic)
-1 Flag in cv::imread indicates that image will be loaded as it is including the alpha channel if present. So, if your image file has alpha channel, your picture(Mat) will be a CV_8UC4 type of image while your pic(Mat) is a 3 channel image. Hence, they won't be same in some cases. But if your picture(Mat) has only 3 channels and its B, G, R channels have same data as data1, data2, data3 respectively then your 'picture' and 'pic' will be same.

Getting masked area to be transparent?

So far i have managed to use masks and get the second image from the first. But what i want is the black area in second image to be transparent (i.e the output i an trying to get is the third image) Here is the code so far. Please advice me on this.
EDIT: Third one is from photoshop
//imwrite parameters
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(100);
//reading image to be masked
image = imread(main_img, -1);
//CV_LOAD_IMAGE_COLOR
namedWindow("output", WINDOW_NORMAL);
//imshow("output", image);
//Creating mask image with same size as original image
Mat mask(image.rows, image.cols, CV_8UC1, Scalar(0));
// Create Polygon from vertices
ROI_Vertices.push_back(Point2f(float(3112),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(1332)));
ROI_Vertices.push_back(Point2f(float(3112),float(958)));
approxPolyDP(ROI_Vertices, ROI_Poly, 1, true);
// Fill polygon white
fillConvexPoly(mask, &ROI_Poly[0] , ROI_Poly.size(), 255, 8, 0);
//imshow("output", mask);
// Create new image for result storage
imageDest = cvCreateMat(image.rows, image.cols, CV_8UC4);
// Cut out ROI and store it in imageDest
image.copyTo(imageDest, mask);
imwrite("masked.jpeg", imageDest, compression_params);
imshow("output", imageDest);
cvWaitKey(0);
This can be done by first setting its alpha value to 0 of the regions that you want to make them fully transparent (255 for others), and then save it to PNG.
To set the alpha value of pixel-(x,y), it can be done:
image.at<cv::Vec4b>(y, x)[3] = 0;
PS: you need to convert it to 4-channel format first if the image is not currently. For example:
cv::cvtColor(image, image, CV_BGR2BGRA);
Updated: It will be easier if you have already computed the mask for the ROI region, where you can simply merge it with the original image (assume having 3 channels) to get the final result. Like:
cv::Mat mask; // 0 for transparent regions, 255 otherwise (serve as the alpha channel)
std::vector<cv::Mat> channels;
cv::split(image, channels);
channels.push_back(mask);
cv::Mat result;
cv::merge(channels, result);