Re: Way to convert a cv::Mat object to a wxBitmap or wxImage
Rossano Paris <[email protected]>
| Newsgroups | gmane.comp.lib.wxwindows.general |
|---|---|
| Message-ID | <[email protected]> |
Hallo at all I'd like to offer my way to achieve what I asked days ago ... Here attached you can find a class useful to convert a cv::Mat object to a wxWidgets image object. There are two different way to make the conversion, one based on opencv functions *(1)*, which is very slow and the faster one *(2),* which is based on this code: link to code <https://github.com/opencv/opencv/blob/master/modules/highgui/src/window_w32.cpp> *(1)* static const wxImage cvMatToWxImage(const cv::Mat& image, wxBitmapType imgtype, std::vector<int> par); *(2)* const wxImage wxhOpenCvTools::cvMatToWxImage(wxWindow* pWindow, const cv::Mat& image) best regards Rossano On Sunday, 12 February 2023 at 14:27:43 UTC+1 Rossano Paris wrote: > Thank you Eric for your tips > I'll take a look at them > > On Thursday, 9 February 2023 at 14:02:50 UTC+1 Eric Jensen wrote: > >> Hello Rossano, >> >> Thursday, February 9, 2023, 12:57:38 PM, you wrote: >> >> RP> Hallo at all. >> >> RP> I came here to ask someone a more conveninet way to convert a cv::Mat >> image >> RP> to BMP. >> RP> Expecially talking about loading such image from memory. >> >> Code: >> https://github.com/PBfordev/wxopencvtest/blob/main/convertmattowxbmp.cpp >> >> Related forum post: >> https://forums.wxwidgets.org/viewtopic.php?f=20&t=47603 >> >> Documentation for bitmap raw pixel access: >> https://docs.wxwidgets.org/trunk/classwx_pixel_data.html >> >> Credit to PB (pbfordev) >> >> Hth >> Eric >> >> >> -- >> >> -- Please read https://www.wxwidgets.org/support/mlhowto.htm before posting. --- You received this message because you are subscribed to the Google Groups "wx-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/wx-users/16d19d15-7243-49b8-8a7c-7934da1ff1d5n%40googlegroups.com.
wxhOpenCvTools.h
(text/x-chdr, 1.3 KB)
/*******************************************************************************
*
* Company name: HOBBIT di Paris Rossano
* File name: ...
* Creation Date: ...
* Creator: Rossano Paris
* Description: ...
*
********************************************************************************/
#ifndef _WXH_OPENCV_UTILITY_H_
#define _WXH_OPENCV_UTILITY_H_
//
//Header files
//
#if defined(_WIN32)
#include <wx/msw/dib.h>
#endif
#include <vector>
#include <opencv2/core/mat.hpp>
#include <wx/image.h>
#include <wx/object.h>
class wxhOpenCvTools : public wxObject
{
wxDECLARE_CLASS(wxhOpenCvTools);
public:
wxhOpenCvTools();
~wxhOpenCvTools();
// Functions
static const wxImage cvMatToWxImage(wxWindow* pWindow, const cv::Mat& image);
static const wxImage cvMatToWxImage(const cv::Mat& image, wxBitmapType imgtype = wxBITMAP_TYPE_BMP, std::vector<int> par = std::vector<int>(0));
private:
// Functions
void Init();
#if defined(_WIN32)
static const wxImage mswMatToWxImage(wxWindow* pWindow, const cv::Mat& image);
static bool mswGetBitmapInformation(HDC dc, int& channels);
static bool mswFillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin);
static bool mswConvertImageToShow(const cv::Mat& src, cv::Mat& dst, bool toRGB);
#endif
};
#endif //_WXH_OPENCV_UTILITY_H_
wxhOpenCvTools.cpp
(text/x-c++src, 6.1 KB)
/*******************************************************************************
*
* Company name: HOBBIT di Paris Rossano
* File name: ...
* Creation Date: ...
* Creator: Rossano Paris
* Description: ...
*
********************************************************************************/
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
/*
Convertion from cv::Mat to wxImage has been possible thanks to this opencv file:
https://github.com/opencv/opencv/blob/master/modules/highgui/src/window_w32.cpp
wxhOpenCvTools::cvMatToWxImage(wxWindow* pWindow, const cv::Mat& image)
is based on such code
*/
//
//Header files
//
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <wx/mstream.h>
#include "wxhOpenCvTools.h"
wxIMPLEMENT_CLASS(wxhOpenCvTools, wxObject );
//Distruttore
wxhOpenCvTools::~wxhOpenCvTools()
{
}
//Costruttore
wxhOpenCvTools::wxhOpenCvTools() : wxObject()
{
Init();
}
void wxhOpenCvTools::Init()
{
}
/*
std::vector<int> par
example:
vector<int> par;
par.push_back(IMWRITE_JPEG_QUALITY);
par.push_back(100);
see:
https://docs.opencv.org/3.4/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56
*/
// Slower
const wxImage wxhOpenCvTools::cvMatToWxImage(const cv::Mat& image, wxBitmapType imgtype, std::vector<int> par)
{
std::vector<unsigned char> imgbuffer;
wxString fmt = wxEmptyString;
wxImage wximg = wxNullImage;
if (!image.empty()) {
switch (imgtype) {
case wxBITMAP_TYPE_BMP:
fmt = ".bmp";
break;
case wxBITMAP_TYPE_PNG:
fmt = ".png";
break;
case wxBITMAP_TYPE_JPEG:
fmt = ".jpg";
break;
case wxBITMAP_TYPE_TIF:
fmt = ".tif";
break;
case wxBITMAP_TYPE_PNM:
fmt = ".pnm";
break;
default:
imgtype = wxBITMAP_TYPE_INVALID;
break;
}
// Supported type
if (imgtype != wxBITMAP_TYPE_INVALID) {
// Convert to vector
cv::imencode(fmt.ToStdString(), image, imgbuffer, par);
// Valid buffer
if (imgbuffer.size() > 0) {
wxMemoryInputStream stream(imgbuffer.data(), imgbuffer.size());
if (!wximg.LoadFile(stream, imgtype)) wximg = wxNullImage;
}
}
}
return wximg;
}
// Faster, but BMP only
const wxImage wxhOpenCvTools::cvMatToWxImage(wxWindow* pWindow, const cv::Mat& image)
{
wxImage wximg = wxNullImage;
if (!image.empty()) {
#if defined(_WIN32)
wximg = mswMatToWxImage(pWindow, image);
#endif
}
return wximg;
}
#if defined(_WIN32)
const wxImage wxhOpenCvTools::mswMatToWxImage(wxWindow* pWindow, const cv::Mat& image)
{
wxImage wximg = wxNullImage;
const int channels = 3;
int bmpchannels = 0;
HDC dc = nullptr;
// retrieves a handle to a device context (DC) for the client area of a specified window
if (pWindow) dc = GetDC(pWindow->GetHWND()); // dc from a window
else dc = GetDC(nullptr); // dc from screen
// Valid dc
if (dc != nullptr) {
// Valid bitmap information
if (mswGetBitmapInformation(dc, bmpchannels)) {
// Get cv image to store converted image
void* pDst = calloc(image.cols * image.rows * bmpchannels, 1);
cv::Mat dst(image.rows, image.cols, CV_8UC3, pDst, (image.cols * channels + 3) & -4);
// Image conversion
if (mswConvertImageToShow(image, dst, false)) {
uchar buffer[sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD)];
BITMAPINFO* binfo = (BITMAPINFO*)buffer;
// Valid bitmap info
if (mswFillBitmapInfo(binfo, image.cols, image.rows, channels * 8, 0)) {
// Create bitmap
HBITMAP bmp = CreateDIBitmap(dc,
&binfo->bmiHeader,
CBM_INIT,
dst.data,
binfo,
DIB_RGB_COLORS);
// Valid bitmap
if (bmp != nullptr) {
// Convert to wxImage
wximg = wxDIB(bmp).ConvertToImage(wxDIB::Convert_AlphaAuto);
// Delete object
DeleteObject(bmp);
}
}
}
// Free resources
std::free(pDst);
}
// Release DC
if (pWindow) ReleaseDC(pWindow->GetHWND(), dc);
else ReleaseDC(nullptr, dc);
}
return wximg;
}
bool wxhOpenCvTools::mswGetBitmapInformation(HDC dc, int& channels)
{
bool vr = false;
// flushes the calling thread's current batch.
GdiFlush();
// Retrieves a handle to an object of the specified type that has been selected into the specified device context (DC).
HGDIOBJ h = GetCurrentObject(dc, OBJ_BITMAP);
// Valid object
if (h != nullptr) {
BITMAP bmp = {};
// Retrieve object attributes
if (GetObject(h, sizeof(bmp), &bmp) != 0) {
channels = bmp.bmBitsPixel / 8;
vr = true;
}
}
return vr;
}
bool wxhOpenCvTools::mswFillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)
{
bool vr = false;
// Valid parameters
if (bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)) {
BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
memset(bmih, 0, sizeof(*bmih));
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = width;
bmih->biHeight = origin ? abs(height) : -abs(height);
bmih->biPlanes = 1;
bmih->biBitCount = (unsigned short)bpp;
bmih->biCompression = BI_RGB;
if (bpp == 8) {
RGBQUAD* palette = bmi->bmiColors;
int i = 0;
for (i = 0; i < 256; i++) {
palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
palette[i].rgbReserved = 0;
}
}
// Return value
vr = true;
}
return vr;
}
bool wxhOpenCvTools::mswConvertImageToShow(const cv::Mat& src, cv::Mat& dst, bool toRGB)
{
int src_depth = src.depth();
bool vr = false;
// Valid depth
if (src_depth != CV_16F && src_depth != CV_32S) {
cv::Mat tmp;
switch (src_depth) {
case CV_8U:
tmp = src;
break;
case CV_8S:
cv::convertScaleAbs(src, tmp, 1, 127);
break;
case CV_16S:
cv::convertScaleAbs(src, tmp, 1 / 255., 127);
break;
case CV_16U:
cv::convertScaleAbs(src, tmp, 1 / 255.);
break;
case CV_32F:
case CV_64F: // assuming image has values in range [0, 1)
src.convertTo(tmp, CV_8U, 255., 0.);
break;
}
// Converts an input image from one color space to another
cv::cvtColor(tmp, dst, toRGB ? cv::COLOR_BGR2RGB : cv::COLOR_BGRA2BGR, dst.channels());
// Return value
vr = true;
}
return vr;
}
#endif