How converting image from picturebox to ::MAT in C++/CLI?
Thank you
You need to cast the Drawing.Image into a Bitmap (assuming that the image REALLY IS a bitmap).
Then lock the System.Drawing.Bitmap, and use the Scan0 property of the BitmapData to access the inner buffer.
System::Drawing::Bitmap ^ bitmapFrame = safe_cast< System::Drawing::Bitmap ^ >(pictureBox1->Image);
BitmapData^ bmpData = bitmapFrame->LockBits(gcnew Rectangle(0, 0, bitmapFrame->Width, bitmapFrame->Height), System::Drawing::Imaging::ImageLockMode::ReadWrite,
bitmapFrame->Format);
try
{
void* data = bmpData.Scan0;
//use the data in the ::Mat constructor.
}
finally { bitmapFrame->UnlockBits(bmpData); }//Remember to unlock!!!
Related
How to read values from a CV_16FC4 matrix?
For example, here how i read from a CV_32FC4:
{
// Create the matrix.
cv::Mat RGBA32F = cv::Mat(16, 16, CV_32FC4);
// Read first value.
const cv::Vec4f color = RGBA32F.at<cv::Vec4f>(0, 0);
}
For CV_16FC4 it would be like:
{
cv::Mat RGBA16F = cv::Mat(16, 16, CV_16FC4);
const /*DataType*/ color = RGBA16F.at</* DataType*/>(0, 0);
}
I don't know what to put for DataType. I am using OpenCV 4.6.0.
Thank you!
I'm learning Emgu.CV, I have successfully run the example, I prefer to read the image from byte array rather than direct from file, and also I prefer to save the result to byte array rather than to save directly to file..
any body can help?
Many thanks
var _img = CvInvoke.Imread(_jpg); // HOW TO READ FROM BYTE ARRAY
var _fd = new Emgu.CV.CascadeClassifier(_face_classifier);
var _img_gray = new UMat();
CvInvoke.CvtColor(_img, _img_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
foreach (Rectangle _face in _fd.DetectMultiScale(_img_gray, 1.1, 10, new System.Drawing.Size(20,20)))
{
CvInvoke.Rectangle(_img, _face, new Emgu.CV.Structure.MCvScalar(255, 255, 255));
}
_img.Save("result.jpg"); // SAVE TO BYTE ARRAY
I've understood your question to be in fact twofold: Converting an image to a byte[], and saving a byte[] to a file. I'll address the easier and latter first:
Saving a byte[] to File
using(FileStream fs = new FileStream("OutputFile.dat",FileMode.OpenOrCreate))
{
BinaryWriter bs = new BinaryWriter(fs);
bs.Write(byteBuffer);
}
Loading a byte[] from File
byte[] byteBuffer;
using (FileStream fs = new FileStream("InputFile.dat", FileMode.OpenOrCreate))
{
BinaryReader br = new BinaryReader(fs);
// Where 0xF0000 is calculated as Image Width x Height x Bit Depth
byteBuffer = br.ReadBytes(0xF0000);
}
Now for the second part; I'm assuming you are familiar with pixel formats and how the true image structure of byte[,,] (or any other depth) is serialized to a single dimension byte[]. If not please do ask.
Create an Image from byte[]
In the following example, the byte[] is created rather than loaded as above, the source of the byte[] is irrelevant so long as it is a correct serialization of a known image dimension and depth.
int width = 640; // Image Width
int height = 512; // Image Height
int stride = 640 * 3; // Image Stide - Bytes per Row (3 bytes per pixel)
// Create data for an Image 512x640 RGB - 983,040 Bytes
byte[] sourceImgData = new byte[0xF0000];
// Pin the imgData in memory and create an IntPtr to it's location
GCHandle pinnedArray = GCHandle.Alloc(sourceImgData, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Create an image from the imgData
Image<Rgb, byte> img = new Image<Rgb, byte>(width, height, stride, pointer);
// Free the memory
pinnedArray.Free();
Convert an Image to byte[]
// Convert the source Image to Bitmap
Bitmap bitmap = sourceImage.ToBitmap();
// Create a BitmapData object from the resulting Bitmap, locking the backing data in memory
BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
// Create an output byte array
byte[] destImgData = new byte[bitmapData.Stride * bitmap.Height];
// Copy the byte array to the destination imgData
Marshal.Copy(bitmapData.Scan0,
destImgData,
0,
destImgData.Length);
// Free the memory
bitmap.UnlockBits(bitmapData);
Is there a way to list all CVPixelBuffer formats for CVPixelBufferCreate() that will not generate error -6683: kCVReturnPixelBufferNotOpenGLCompatible when used with CVOpenGLESTextureCacheCreateTextureFromImage()?
This lists all the supported CVPixelBuffer formats for CVPixelBufferCreate(), but does not guarantee that CVOpenGLESTextureCacheCreateTextureFromImage() will not return the error above.
I guess my desired list should be a subset of this one.
Based on the answer from Adi Shavit above, here's a full code snippet (Objective-C) that you can use to print all the current OpenGL ES compatible pixel formats:
+ (void)load {
#autoreleasepool {
printf("Core Video Supported Pixel Format Types:\n");
CFArrayRef pixelFormatDescriptionsArray = CVPixelFormatDescriptionArrayCreateWithAllPixelFormatTypes(kCFAllocatorDefault);
for (CFIndex i = 0; i < CFArrayGetCount(pixelFormatDescriptionsArray); i++) {
CFNumberRef pixelFormatFourCC = (CFNumberRef)CFArrayGetValueAtIndex(pixelFormatDescriptionsArray, i);
if (pixelFormatFourCC != NULL) {
UInt32 value;
CFNumberGetValue(pixelFormatFourCC, kCFNumberSInt32Type, &value);
NSString * pixelFormat;
if (value <= 0x28) {
pixelFormat = [NSString stringWithFormat:#"Core Video Pixel Format Type 0x%02x", (unsigned int)value];
} else {
pixelFormat = [NSString stringWithFormat:#"Core Video Pixel Format Type (FourCC) %c%c%c%c", (char)(value >> 24), (char)(value >> 16), (char)(value >> 8), (char)value];
}
CFDictionaryRef desc = CVPixelFormatDescriptionCreateWithPixelFormatType(kCFAllocatorDefault, (OSType)value);
CFBooleanRef OpenGLESCompatibility = (CFBooleanRef)CFDictionaryGetValue(desc, kCVPixelFormatOpenGLESCompatibility);
printf("%s: Compatible with OpenGL ES: %s\n", pixelFormat.UTF8String, (OpenGLESCompatibility != nil && CFBooleanGetValue(OpenGLESCompatibility)) ? "YES" : "NO");
}
}
printf("End Core Video Supported Pixel Format Types.\n");
}
}
You can put this snippet anywhere in a Objective-C category or class to print which pixel format are compatible and which aren't.
For completeness purposes, here are all the pixel formats currently compatible with OpenGL ES as of iOS 10.2.1:
L565
5551
L555
2vuy
yuvs
yuvf
L008
L016
2C08
2C16
BGRA
420v
420f
420e
411v
411f
422v
422f
444v
444f
L00h
L00f
2C0h
2C0f
RGhA
RGfA
Answering myself... after further study of this link.
The function CVPixelFormatDescriptionArrayCreateWithAllPixelFormatTypes() provides all the supported formats on a particular device (and OS). Once the fourCC value is found as shown in the link, you can use CVPixelFormatDescriptionCreateWithPixelFormatType() to get a dictionary with various fields describing each format.
This looks something like this:
UInt32 value;
CFNumberGetValue(pixelFormatFourCC, kCFNumberSInt32Type, &value);
auto desc = CVPixelFormatDescriptionCreateWithPixelFormatType(kCFAllocatorDefault, (OSType)value);
auto OpenGLCompatibility = (CFBooleanRef)CFDictionaryGetValue(desc, kCVPixelFormatOpenGLCompatibility);
auto OpenGLESCompatibility = (CFBooleanRef)CFDictionaryGetValue(desc, kCVPixelFormatOpenGLESCompatibility);
If OpenGLESCompatibility is true then this format is OpenGL ES compatible.
How do I convert an array<System:Byte>^ to a Mat in openCV. I am being passed a array<System:Byte>^ in c++/cli, but I need to convert it to Mat to be able to read it and display it.
You can use constructor Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP). The conversion may look like this.
void byteArray2Mat(array<System::Byte>^ byteArray, cv::Mat &output)
{
pin_ptr<System::Byte> p = &byteArray[0];
unsigned char* pby = p;
char* pch = reinterpret_cast<char*>(pby);
// assuming your input array has 2 dimensions.
int rows = byteArray->GetLength(0);
int cols = byteArray->GetLength(1);
output = cv::Mat(rows, cols, CV_8UC1, (void*)pch)
}
I don't have c++/CLI to test the program and this may not be most efficient method. At least it should give you an idea on how to get started.
I'm looking for a solution to display successive frames in one window using OpenCV. I have a sequence of images (001.jpg, 002.jpg, 003.jpg, etc.), but not a video. I have to display them within a loop.
The standard code to display an image is:
IplImage* src = cvLoadImage("001.jpg");
cvNamedWindow("My pic");
cvShowImage("My pic",src);
cvWaitKey();
As Link suggests, one option would be to write a function that automatically generates the correct filename, for example:
void loadImage(IplImage *image, int number)
{
// Store path to directory
char filename[100];
strcpy(filename, "/path/to/files");
// Convert integer to char
char frameNo[10];
sprintf(frame, "%03i", number);
// Combine to generate path
strcat(filename, frameNo);
strcat(filename, ".bmp");
// Use path to load image
image = cvLoadImage(filename);
}
This could then be used in a loop for a known number of images
IplImage *im;
for (int i = 0; i < nImages; ++i)
{
loadImage(im, i);
/*
Do stuff with im
*/
}
An alternative option would be to investigate the boost directory iterator.
#Chris code works, I want to add an even simpler routine
void loadImage()
{
int nImages = 6;
for (int i = 0; i < nImages; ++i)
{
IplImage *image;
char filename[100];
strcpy(filename, "images/");
char frameNo[10];
sprintf(frameNo, "%03i", i);
strcat(filename, frameNo);
strcat(filename, ".jpg");
image = cvLoadImage(filename);
cvNamedWindow("pic");
cvShowImage("pic",image);
cvWaitKey(1000);
}
}
Try to use XML/YAML persistence mechanisms of OpenCV. Write a list of image paths for loading and use a loop to read those paths and load images. In the example of stereo calibration such a list is used (there is a directory with examples installed with OpenCV).