繁体   English   中英

包装用于C#的OpenCv C ++代码

[英]Wrapping OpenCv C++ code for use in C#

我正在尝试包装一个使用OpenCvC++类,以便我可以在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使与maxTarget / 2匹配的行索引变亮 - 意思是,当我向右滑动滑块时,为了获得更大的值,我会使图像的一部分变亮休息就像原来一样。 (例如:如果maxTarget为300,则行#0和行#150之间的所有行都将更亮,其余的将与原始行类似)。

2)另一方面,如果我为maxTarget交叉值960然后应用程序崩溃并出现以下错误(即使代码被try/catch包围):

“类型异常:'System.AccessViolationException'发生在ImageBrightenerWrapper.dll中,但未在用户代码中处理。附加信息:尝试读取或写入受保护的内存。这表明其他内存已损坏。”

我在这做错了什么?

所以我找到了两个主要问题来解决这个问题:

1)我错误地混合了C#代码中的参数顺序。

2)我不得不更换以下行:

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

有了这个:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM