2016-03-08 52 views
3

我想包裝一個C++類,它使用OpenCv,以便我可以在C#中使用它。包裝在C#中使用的OpenCv C++代碼

我有C++功能:

void ImageBrightener::BrightenImage(const cv::Mat& sourceImage, cv::Mat& targetImage, int maxTarget) 
{ 
    double scaleFactor; 
    double shiftFactor = 0; 
    double minVal = DBL_MAX, minValTemp; 
    double maxVal = -DBL_MAX, maxValTemp; 
    auto numPixels = 0; 
    const auto RANGE_TOP_EXTEND = 10; 
    const auto RANGE_BOTTOM_EXTEND = 7; 

    assert(sourceImage.type() == CV_8UC1); 
    assert(sourceImage.channels() == 1); 

    cv::minMaxIdx(sourceImage, &minValTemp, &maxValTemp); 
    if (minValTemp < minVal) 
    minVal = minValTemp; 
    if (maxValTemp>maxVal) 
     maxVal = maxValTemp; 

    numPixels += sourceImage.cols * sourceImage.rows; 

    if (maxVal == minVal) 
    { 
     sourceImage.convertTo(targetImage, CV_8UC1, 1, shiftFactor); 
     return; 
    } 

    // Account for prev/curr ROI differences - add a bit to the range 
    maxVal += RANGE_TOP_EXTEND; 
    minVal -= RANGE_BOTTOM_EXTEND; 
    minVal = std::max(minVal, 0.); 

    if ((maxVal - minVal) < maxTarget) 
    { 
     scaleFactor = maxTarget/(maxVal - minVal); 
     shiftFactor = -1 * scaleFactor * minVal; 

     sourceImage.convertTo(targetImage, CV_8UC1, scaleFactor, shiftFactor); 
     return; 
    } 

    auto fltMinVal = static_cast<float>(minVal) - 1; 
    auto fltMaxVal = static_cast<float>(maxVal) + 1; 

    // Check histogram 
    const unsigned int *currval; 

    #define BINS (100) 
    #define CUTOFF (0.00003) 
    #define RESCUTOFF (0.2) 

    int hist[BINS] = { 0 }; 
    int bin; 

    numPixels += sourceImage.cols * sourceImage.rows; 
    for (auto rowIndex = 0; rowIndex < sourceImage.rows; rowIndex++) 
    { 
     currval = sourceImage.ptr<unsigned>(rowIndex, 0); 
     for (auto colIndex = 0; colIndex < sourceImage.cols; colIndex++) 
     { 
      bin = static_cast<int>((BINS - 1) * ((*currval - fltMinVal)/(fltMaxVal - fltMinVal))); 
      assert(bin >= 0 && bin < BINS); 
      hist[bin]++; 
      ++currval; 
     } 
    } 

    double ratio; 
    auto sum = 0; 
    int i; 
    for (i = BINS - 1; i >= 0; i--) 
    { 
     sum += hist[i]; 
     ratio = static_cast<double>(sum)/static_cast<double>(numPixels); 
     if (ratio > CUTOFF) 
      break; 
    } 
    if (static_cast<double>(BINS - i)/static_cast<double>(BINS) > RESCUTOFF) 
     fltMaxVal = fltMinVal + ((i + 2)*(fltMaxVal - fltMinVal))/BINS; 

    // Account for prev/curr ROI differences - add a bit to the range 
    fltMaxVal += RANGE_TOP_EXTEND; 
    fltMinVal -= RANGE_BOTTOM_EXTEND; 
    fltMinVal = std::max(fltMinVal, 0.f); 

    scaleFactor = maxTarget/(fltMaxVal - fltMinVal); 
    shiftFactor = -1 * scaleFactor * fltMinVal; 

    sourceImage.convertTo(targetImage, CV_8UC1, scaleFactor, shiftFactor); 
} 

當我用下面C++代碼測試該代碼:

int main() 
{ 
    auto* m_imageBrightener = new ImageBrightener(); 
    auto inputImage = cv::imread("E:\\ttt.png", CV_LOAD_IMAGE_UNCHANGED); 

    cv::Mat outputImage; 

    m_imageBrightener->BrightenImage(inputImage, outputImage, 2000); 
    cv::imwrite("E:\\new_ttt.png", outputImage); 
} 

一切正常,代碼做什麼應該,這是獲得黑暗的8位圖像,並照亮它(我嘗試用500代替200 - 它工作正常)。如預期的那樣,new_ttt.png圖像變亮。

在另一方面,我有以下/Clr代碼,它包裝在C++代碼和從它創建一個DLL

array<System::Byte>^ ImageProcessing::ImageBrightenerWrapper::BrightenImage(array<System::Byte>^ sourceImage, int imageWidth, int imageHeight, int maxTarget) 
{ 
    array<System::Byte>^ targetImage = (array<System::Byte>^)sourceImage->Clone(); 

    pin_ptr<System::Byte> sourcePointer = &sourceImage[0]; 
    pin_ptr<System::Byte> targetPointer = &targetImage[0]; 

    cv::Mat sourceMat(imageHeight, imageWidth, CV_8UC1, (unsigned short*)sourcePointer); 
    cv::Mat targetMat(imageHeight, imageWidth, CV_8UC1, (unsigned short*)targetPointer); 

    targetMat.setTo(0); 
    m_imageBrightener->BrightenImage(sourceMat, targetMat, maxTarget); 

    uchar* tempPointer; 
    for (auto rowIndex = 0; rowIndex < imageHeight; ++rowIndex) 
    { 
     tempPointer = targetMat.ptr<uchar>(rowIndex); 
     for (auto colIndex = 0; colIndex < imageWidth; ++colIndex) 
      targetImage[rowIndex + colIndex] = tempPointer[colIndex]; 
    } 

    return targetImage; 
} 

有了它,我也有一個WPF應用程序,它具有控制的滑塊參數maxTarget

這是我面對:

1),一方面,爲maxTarget 0和960之間的任意值亮相匹配maxTarget/2行索引 - 這意味着,當我滑塊向右滑動,爲了獲得更大的價值,我得到了一部分明亮的圖像,其餘部分與原始圖像一樣。 (例如:如果maxTarget是300,那麼行#0和行#150之間的所有行將會更亮,其餘的將像原始行)。

2)。另一方面,如果我穿越值,如果960爲maxTarget然後應用程序崩潰與以下錯誤(即使代碼與try/catch包圍):

「類型的例外: ImageBrightenerWrapper.dll中出現'System.AccessViolationException',但未在用戶代碼中處理。附加信息:試圖讀取或寫入受保護的內存,這表明其他內存已損壞。

我在這裏做錯了什麼?

回答

1

於是我發現了兩個主要問題要解決的問題:

1)我誤混入從C#代碼的參數順序。

2)我不得不替換下面的行:

cv::Mat sourceMat(imageHeight, imageWidth, CV_8UC1, (unsigned short*)sourcePointer); 

有了這一個:

cv::Mat sourceMat(imageHeight, imageWidth, CV_16UC1, (unsigned short*)sourcePointer);