How to convert Single Channel IplImage* to Bitmap^ - image

How can I convert single channel IplImage (grayscale), depth=8, into a Bitmap?
The following code runs, but displays the image in 256 color, not grayscale. (Color very different from the original)
btmap = gcnew Bitmap(
cvImg->width ,
cvImg->height ,
cvImg->widthStep ,
System::Drawing::Imaging::PixelFormat::Format8bppIndexed,
(System::IntPtr)cvImg->imageData)
;
I believe my problem lies in the PixelFormat. Ive tried scaling the image to 16bit and setting the pixel format to 16bppGrayscale, but this crashes the form when uploading the image.
The destination is a PicturePox in a C# form.Thanks.

You need to create ColorPalette instance, fill it with grayscale palette and assign to btmap->Palette property.
Edit: Actually, creating ColorPalette class is a bit tricky, it is better to modify color entries directly in btmap->Palette. Set these entries to RGB(0,0,0), RGB(1,1,1) ... RGB(255,255,255). Something like this:
ColorPalette^ palette = btmap->Palette;
array<Color>^ entries = palette->Entries;
for ( int i = 0; i < 256; ++i )
{
entries[i] = Color::FromArgb(i, i, i);
}

int intStride = (AfterHist.width * AfterHist.nChannels + 3) & -4;
Bitmap BMP = new Bitmap(AfterHist.width,
AfterHist.height, intStride,
PixelFormat.Format24bppRgb, AfterHist.imageData);
this way is correct to create a bitmap of a IPLimage.

Related

How do I create and initialise a DXGI_FORMAT_NV12 resource in DX12 (source is AVFrame)

I'm trying to create an NV12 resource as source for a video encoder in DX12. While I intend to eventually populate a resource from GPU, what I'm trying to do now is take an ffmpeg AVFrame I already have (in AV_PIX_FMT_YUV420P format) and create a texture in DXGI_FORMAT_NV12 format using that data.
I understand the NV12 format (https://learn.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#nv12) has U and V interleaved while the AV_PIX_FMT_YUV420P doesn't.
My main question is what does the D3D12_RESOURCE_DESC look like for an NV12 texture - do I tell it I need more than one array/mip level to make it planar? Or do I just give it a single memory address with both planes layed out as per the NV12 format, and it figures out subresources for me based on the format?
I understand that to read the data I define two SRVs, one for Y mapped to the Red channel and a second for U and V, but it's how I initialise it that's confusing me.
Just create the resource as normal, and then when you query the layout description, it will be planar.
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Format = DXGI_FORMAT_NV12;
desc.MipLevels = 1;
desc.DepthOrArraySize = 1;
desc.Width = 1024;
desc.Height = 720;
desc.SampleDesc.Count = 1;
const CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
ComPtr<ID3D12Resource> res;
HRESULT hr = device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(res.GetAddressOf()));
if (FAILED(hr))
{
// error
}
D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { DXGI_FORMAT_NV12, 0 };
if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))
{
formatInfo = {};
}
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint[2] = {};
UINT numRows;
UINT64 rowBytes, totalBytes;
device->GetCopyableFootprints(&desc, 0, 2, 0, footprint, &numRows, &rowBytes, &totalBytes);
The formatInfo.PlaneCount is 2, which is why you have to ask for two subresources.
footprint[0].Format is DXGI_FORMAT_R8_TYPELESS with 1024x720 size. The footprint[0].Offset is likely 0.
footprint[1].Format is DXGI_FORMAT_R8G8_TYPELESS with 512x360 size. The footprint[1].Offset is something other than 0.
In Direct3D 12 Video the layouts are very simple to understand. In Direct3D 11 Video, it was all implicitly defined so it was a bit of a mess. That said, DDS files were defined as non-planar data, so you may want to examine how these are handled in DirectXTex.

How to detect numbers/digits via builtin OcrEngine class

I have troubles detecting digits/numbers in an image with the Windows UWP OCR-Engine from C++/CX.
I need to detect the number in the following Image
I tried it by using the builtin method for Windows 10 UWP: OcrEngine with the following code:
...
cv::Mat croppedImage = imread("digit.png");
WriteableBitmap^ bit1 = ref new WriteableBitmap(croppedImage.cols, croppedImage.rows);
SoftwareBitmap^ bit2 = bit2->CreateCopyFromBuffer(bit1->PixelBuffer, BitmapPixelFormat::Bgra8, bit1->PixelWidth, bit1->PixelHeight);
Windows::Globalization::Language^ l = ref new Windows::Globalization::Language("de");
OcrEngine^ ocrEngine = OcrEngine::TryCreateFromLanguage(l);
IAsyncOperation<OcrResult^>^ ao = ocrEngine->RecognizeAsync(bit2);
task_completion_event<Platform::String^> purchaseCompleted;
auto deviceEnumTask = create_task(ao);
deviceEnumTask.then([this](OcrResult^ result)
{
App1::MainPage::findNumber(result->Text);
});
...
void App1::MainPage::findNumber(Platform::String^ text)
{
//Do something with String
}
My Problem is now, that the inserted string in findNumber is always null. I tried with different pictures as input but always the same result: NULL.
Is there an easier way to get the digits in this images in C++/CX?
What could be the problem? Converting the image?
The problem was the conversion of the WriteableBitmap to a SoftwareBitmap WriteableBitmap^ bit1 = ref new WriteableBitmap(croppedImage.cols, croppedImage.rows);
// Get access to the pixels
IBuffer^ buffer = bit1->PixelBuffer;
unsigned char* dstPixels;
// Obtain IBufferByteAccess
ComPtr<IBufferByteAccess> pBufferByteAccess;
ComPtr<IInspectable> pBuffer((IInspectable*)buffer);
pBuffer.As(&pBufferByteAccess);
// Get pointer to pixel bytes
pBufferByteAccess->Buffer(&dstPixels);
memcpy(dstPixels, croppedImage.data, croppedImage.step.buf[1] * croppedImage.cols*croppedImage.rows);
SoftwareBitmap^ bit2= ref new SoftwareBitmap(BitmapPixelFormat::Bgra8, croppedImage.cols, croppedImage.rows);
//SoftwareBitmap^ bit2 =
bit2->CopyFromBuffer(bit1->PixelBuffer);

Display bmp image and text in List Control in MFC

I want to display bmp image and text in list control in MFC ,
It should display different bmp image for different item , but it display same bmp for all the items
Here is my code
CListCtrl m_cParentListContrl;
CImageList m_ImageList[3];
m_ImageList[0].Create(IDB_BMP_LISTCTRL,128,1,RGB(150,150,100));
m_ImageList[1].Create(IDB_BMP_CHECKBOX,128,1,RGB(150,150,100));
m_ImageList[2].Create(IDB_BMP_COMBOBOX,128,1,RGB(150,150,100));
m_cParentListContrl.SetImageList(m_ImageList,LVSIL_NORMAL);
for(int i = 0 ; i < 3 ; i++)
{
val.Format(_T("List ::%d"),i);
//third parameter for index of image to be displayed
// if that replaced by i to 0 then it display single image else not
m_cParentListContrl.InsertItem(i,val,i);
}
Thanks
Assuming you don't want to reduce your current 3 bitmaps to one continuous strip bitmap with your 3 images one after each other:
CImageList m_ImageList;
m_ImageList.Create(128,128, ILC_COLOR24, 3, 1);
m_ImageList.SetImageCount(3);
CBitmap bmpListCtrl;
bmpListCtrl.LoadBitmap(IDB_BMP_LISTCTRL);
m_ImageList.Replace(0, bmpListCtrl, (CBitmap*)NULL);
CBitmap bmpCheckBox;
bmpCheckBox.LoadBitmap(IDB_BMP_CHECKBOX);
m_ImageList.Replace(1, bmpCheckBox, (CBitmap*)NULL);
CBitmap bmpComboBox;
bmpComboBox.LoadBitmap(IDB_BMP_COMBOBOX);
m_ImageList.Replace(2, bmpComboBox, (CBitmap*)NULL);

load a thumbnail on QListWidget with reduced resolution

I need to reduce the resolution of the images that I add and show in a QListWidgtet.
Now I use the next code but it does not show all the images because they are being loaded with full resolution
void ImagesWizard::on_pbAddImages_clicked()
{
QFileDialog dialog(this);
dialog.setDirectory(mInitPath);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter(trUtf8("Images (*.jpg *.png *.tif *.tiff *.bmp);; JPG (*.jpg);; PNG (*.png);; TIF (*.tif *.tiff);; BMP (*.bmp);;"));
QStringList filesToLoad;
if (dialog.exec())
filesToLoad = dialog.selectedFiles();
if (filesToLoad.count()!=0) {
QListWidget *localPathList= new QListWidget();
localPathList->setViewMode(QListWidget::IconMode );
localPathList->setIconSize(QSize(100,100));
localPathList->setResizeMode(QListWidget::Adjust);
localPathList->setSelectionMode(QAbstractItemView::MultiSelection);
for (int var = 0; var < filesToLoad.count(); ++var) {
if (!mImagesList->contains(filesToLoad[var])) {
QFileInfo fileInfo(filesToLoad[var]);
QString filename(fileInfo.fileName());
QListWidgetItem *listItem = new QListWidgetItem(QIcon(filesToLoad[var]),filename);
localPathList->addItem(listItem);
mImagesList->append(filesToLoad[var]);
}
}
pbNext->setFocus();
}
}
Is there any way to resize the resolution in of the QIcon to optimice the time consumed to load the images and to show all the images added?
Now if I load a lot of images the last QListWidgetItems only add the name.
Thanks for your help
Use QImage first to scale the image and construct the icon from the resulting pixmap.
QSize desiredSize;
Qimage orig(filesToLoad[var]);
Qimage scaled = orig.scaled(
desiredSize,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
QListWidgetItem *listItem = new QListWidgetItem(QIcon(Qpixmap::fromImage(scaled)),filename);
It is very common to store the presized image too on the disk, to avoid the two step conversion process.

Writing a multipage tif to file in matlab

I'm trying to write a a multipage (1024 pages to be exact) to file.
for frame=1:num_images
imwrite(output(:,:,frame), 'output.tif', 'tif', 'WriteMode', 'append', 'compression', 'none');
end
I tried this, but writing Int32 to tiff is not supported by imwrite.
I've also tried
tiffObj = Tiff('output.tif', 'w');
tiffObj.setTag('ImageLength', x_size);
tiffObj.setTag('ImageWidth', y_size);
tiffObj.setTag('Photometric', Tiff.Photometric.MinIsBlack);
tiffObj.setTag('BitsPerSample', 32);
tiffObj.setTag('SamplesPerPixel', 1);
tiffObj.setTag('RowsPerStrip', 64);
tiffObj.setTag('SampleFormat', Tiff.SampleFormat.Int);
tiffObj.setTag('TileWidth', 128);
tiffObj.setTag('TileLength', 128);
tiffObj.setTag('Compression', Tiff.Compression.None);
tiffObj.setTag('PlanarConfiguration',Tiff.PlanarConfiguration.Chunky);
tiffObj.setTag('Software', 'MATLAB');
tiffObj.write(output);
tiffObj.close();
The tif I imread() has 1 SamplesPerPixel per frame, but when I try to use the same value I get
SamplesPerPixel is 1, but the number of image planes provided was 1204.
If I set it to 1204 Imagej complains
Unsupported SamplesPerPixel: 1204
This is rather frustrating.
The correct way to write multiple pages to a TIFF file is to call Tiff.writeDirectory after each page (2D image) has been written. I agree, the MATLAB documentation is not very clear there, knowing LibTIFF helps in using the Tiff class. For example:
image = zeros([140,160,16],'uint8'); % this is the image we'll write, should have some actual data in it...
t = Tiff('testing.tif','w');
tagstruct.ImageLength = size(image,1);
tagstruct.ImageWidth = size(image,2);
tagstruct.SampleFormat = 1; % uint
tagstruct.Photometric = Tiff.Photometric.MinIsBlack;
tagstruct.BitsPerSample = 8;
tagstruct.SamplesPerPixel = 1;
tagstruct.Compression = Tiff.Compression.Deflate;
tagstruct.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
for ii=1:size(image,3)
setTag(t,tagstruct);
write(t,image(:,:,ii));
writeDirectory(t);
end
close(t)

Resources