2017-08-17 105 views
4

我從我的C++類中創建了一個C DLL,它使用OpenCV進行圖像操作,並且希望在我的C#應用​​程序中使用此DLL。目前,這是多麼我已經實現了它:從C#發送到C++ OpenCV後獲取扭曲的圖像?

#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#應用程序發送的數據被創建後,我面對的圖像像這樣:

有問題的例子:

enter image description here

很好的例子:

enter image description here

+1

看起來步幅/間距不正確,例如步驟arg將對齊內存,以便出於性能原因每行適合某些字節對齊。這就是爲什麼下一個像素不對齊的原因,你需要看看step/stride的大小是什麼,這可能需要通過,這樣當它訪問後續行時,它會在內存中使用正確的偏移量,所以我不能建議任何其他事情,因爲我純粹用C++編寫的openCV,但這是你的問題,關於圖像錯誤 – EdChum

+1

我在這裏找到相關的東西:https://msdn.microsoft.com/en-us/library/system.drawing。 imaging.bitmapdata.stride(v = vs.110).aspx我沒有用c#編寫代碼,但它看起來應該檢查一下,它可能與您找到的圖像寬度不一樣。它可能是'圖像寬度*每個通道的num字節數*通道數+填充'。該文檔指出該數字將是4字節對齊的 – EdChum

+1

如果我們計算字節數,則有問題的圖像的寬度爲1414,圖像爲24位,帶有3 * 8位顏色通道:'1414 * 3 = 4242如果我們除以4'4242/4 = 1060.5',則可以看到我們剩下的是'0.5',這意味着由於0.5 * 4字節= 2字節,步幅將被設置爲'4244'檢查是否是這種情況 – EdChum

回答

2

你最初的問題是處理所謂的步幅或圖像緩衝區間距。 基本上,由於性能原因,像素行值可能與內存對齊,這裏我們看到,在您的情況下,它會導致像素行不對齊,因爲行大小不等於像素行寬。

一般的情況是:

resolution width * bit-depth (in bytes) * num of channels + padding 
你的情況

bitmap類狀態:

跨距是像素的單行(掃描線)的寬度, 四捨五入到一個四字節的邊界

所以,如果我們看看有問題的圖像,它有一個1414像素寬度的分辨率,thi s是一個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這將加載圖像並隨時轉換灰度。

+0

非常感謝。這裏是新的問題,我試圖徹底: https://stackoverflow.com/questions/45753429/resizing-the-image-in-c-sharp-and-sending-it-to-opencv-結果,在扭曲,IMAG – Breeze