将图像从 C# 发送到 C++ 中的 OpenCV 后图像失真?
Getting distorted images after sending them from C# to OpenCV in C++?
我从我的 C++ class 创建了一个 C DLL,它使用 OpenCV
进行图像处理,我想在我的 C# 应用程序中使用这个 DLL。目前,我是这样实现的:
#ifdef CDLL2_EXPORTS
#define CDLL2_API __declspec(dllexport)
#else
#define CDLL2_API __declspec(dllimport)
#endif
#include "../classification.h"
extern "C"
{
CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results = 2);
//...
}
C#相关代码:
DLL 导入部分:
//Dll import
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(IntPtr img, uint height, uint width, byte[] out_result, out int out_result_length, int top_n_results = 2);
将图像发送到 DLL 的实际函数:
//...
//main code
private string Classify(int top_n)
{
byte[] res = new byte[200];
int len;
Bitmap img = new Bitmap(txtImagePath.Text);
BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
Classify_Image(bmpData.Scan0, (uint)bmpData.Height, (uint)bmpData.Width, res, out len, top_n);
img.UnlockBits(bmpData); //Remember to unlock!!!
//...
}
和 DLL 中的 C++ 代码:
CDLL2_API void Classify_Image(unsigned char* img_pointer, unsigned int height, unsigned int width,
char* out_result, int* length_of_out_result, int top_n_results)
{
auto classifier = reinterpret_cast<Classifier*>(GetHandle());
cv::Mat img = cv::Mat(height, width, CV_8UC3, (void*)img_pointer, Mat::AUTO_STEP);
std::vector<Prediction> result = classifier->Classify(img, top_n_results);
//...
*length_of_out_result = ss.str().length();
}
这对某些图像非常有效,但对其他图像不起作用,例如,当我尝试 imshow
Classify_Image
中的图像时,它是根据发送的数据创建的C# 应用程序,我遇到这样的图像:
有问题的例子:
很好的例子:
您最初的问题是关于图像缓冲区的步幅或间距。
基本上出于性能原因像素行值可以内存对齐,这里我们看到在您的情况下它导致像素行不对齐,因为行大小不等于像素行宽度。
一般情况是:
resolution width * bit-depth (in bytes) * num of channels + padding
在您的情况下 bitmap class 状态:
The stride is the width of a single row of pixels (a scan line),
rounded up to a four-byte boundary
因此,如果我们查看有问题的图像,它的分辨率为 1414 像素宽度,这是一个 8 位 RGB 位图,因此如果我们进行数学计算:
1414 * 1 * 3 (we have RGB so 3 channels) = 4242 bytes
所以现在除以 4 个字节:
4242 / 4 = 1060.5
所以我们剩下 0.5 * 4 bytes = 2 bytes padding
所以步幅实际上是 4244 字节。
所以这需要通过,这样步幅才正确。
看看你在做什么,我会将文件作为内存传递给你的 openCV dll,这应该能够调用 imdecode
来嗅探文件类型,另外你可以传递标志cv::IMREAD_GRAYSCALE
这将加载图像并动态转换灰度。
我从我的 C++ class 创建了一个 C DLL,它使用 OpenCV
进行图像处理,我想在我的 C# 应用程序中使用这个 DLL。目前,我是这样实现的:
#ifdef CDLL2_EXPORTS
#define CDLL2_API __declspec(dllexport)
#else
#define CDLL2_API __declspec(dllimport)
#endif
#include "../classification.h"
extern "C"
{
CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results = 2);
//...
}
C#相关代码:
DLL 导入部分:
//Dll import
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(IntPtr img, uint height, uint width, byte[] out_result, out int out_result_length, int top_n_results = 2);
将图像发送到 DLL 的实际函数:
//...
//main code
private string Classify(int top_n)
{
byte[] res = new byte[200];
int len;
Bitmap img = new Bitmap(txtImagePath.Text);
BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
Classify_Image(bmpData.Scan0, (uint)bmpData.Height, (uint)bmpData.Width, res, out len, top_n);
img.UnlockBits(bmpData); //Remember to unlock!!!
//...
}
和 DLL 中的 C++ 代码:
CDLL2_API void Classify_Image(unsigned char* img_pointer, unsigned int height, unsigned int width,
char* out_result, int* length_of_out_result, int top_n_results)
{
auto classifier = reinterpret_cast<Classifier*>(GetHandle());
cv::Mat img = cv::Mat(height, width, CV_8UC3, (void*)img_pointer, Mat::AUTO_STEP);
std::vector<Prediction> result = classifier->Classify(img, top_n_results);
//...
*length_of_out_result = ss.str().length();
}
这对某些图像非常有效,但对其他图像不起作用,例如,当我尝试 imshow
Classify_Image
中的图像时,它是根据发送的数据创建的C# 应用程序,我遇到这样的图像:
有问题的例子:
很好的例子:
您最初的问题是关于图像缓冲区的步幅或间距。 基本上出于性能原因像素行值可以内存对齐,这里我们看到在您的情况下它导致像素行不对齐,因为行大小不等于像素行宽度。
一般情况是:
resolution width * bit-depth (in bytes) * num of channels + padding
在您的情况下 bitmap class 状态:
The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary
因此,如果我们查看有问题的图像,它的分辨率为 1414 像素宽度,这是一个 8 位 RGB 位图,因此如果我们进行数学计算:
1414 * 1 * 3 (we have RGB so 3 channels) = 4242 bytes
所以现在除以 4 个字节:
4242 / 4 = 1060.5
所以我们剩下 0.5 * 4 bytes = 2 bytes padding
所以步幅实际上是 4244 字节。
所以这需要通过,这样步幅才正确。
看看你在做什么,我会将文件作为内存传递给你的 openCV dll,这应该能够调用 imdecode
来嗅探文件类型,另外你可以传递标志cv::IMREAD_GRAYSCALE
这将加载图像并动态转换灰度。