Преобразование кода c в код c# для сценария сопоставления цветов изображений

#c# #c #opencv #emgucv #code-conversion

Вопрос:

Я пытаюсь создать сценарий для сопоставления цветов между двумя изображениями с помощью EmguCV.

Мне удалось найти код, который делает именно то, что я хочу, здесь, однако он написан на C , с которым я не очень хорошо знаком.

Я уверен, что многие из этих вещей являются базовыми проблемами C -> C#, даже если вы не знакомы с EmguCV / OpenCV…

До сих пор я в тупике на следующем (см. Код ниже).

  1. «маска(p)» — маска имеет тип Mat, и это приводит к ошибке в C#: «ожидается имя метода». Я предполагаю, что код пытается индексировать маску, но не уверен, как это сделать. В коде довольно много таких примеров.
  2. ‘chns[i]’ — вероятно, аналогично приведенному выше, chns снова относится к типу Mat, и это приводит к ошибке «Невозможно применить индексацию с помощью [] к выражению типа Mat».
  3. С «маской(p)» выше и другими различными примерами, как только проблема выше будет исправлена, я подозреваю, что возникнет еще одна проблема при сравнении мата с целым числом для перебора — возможно, это просмотр столбцов или строк, я не уверен. (Я имею в виду, например, » если (маска(p) > 0)» )
  4. С ‘CvInvoke.Разделение(src, chns)» создает ошибку «Не удается преобразовать из» Системы.Коллекции.Generic.List<Emgu.CV.Mat> в Emgu.CV.IOutputArray’. Я предполагаю, что мне нужно определить chns и chns1 для IOutputArray — хотя я не уверен, как это сделать — для объявления IOutputArray с использованием нового OutputArray требуется ссылка IntPtr (возможно, ‘new Mat()’? и родитель — не совсем уверен, что здесь требуется. аренду смотрите ниже.

Я запустил исходный код C через конвертер C в C#, чтобы избавиться от очевидных проблем, и внес столько изменений, сколько смог, чтобы преобразовать вызовы OpenCV в EmguCV, и у меня осталось следующее. Любая помощь в расшифровке оставшихся частей будет принята с величайшей благодарностью.

Дальнейшие предположения, которые я применил:

  1. При ссылке на » Мат «в именах методов я не думаю, что C# требует, чтобы вы указывали глубину, как вы делаете в C , поэтому я удалил ссылки и, но вместо этого обновил типы глубины при объявлении матов, например» новый мат(1, 256, тип глубины.Cv64F, 1);» (в случае double)
  2. Обновлены типы переменных, например «uchar» -> «байт»
  3. Другие преобразования были отменены, кроме очевидных преобразований OpenCV -> EmguCV, которые явно верны.

Код, который я должен до сих пор:

 public static class EmguCVColourMatchingHelper
{

    // Compute histogram and CDF for an image with mask
    // C  : void do1ChnHist(const Mat_<uchar> amp;img, const Mat_<uchar> amp;mask, Mat_<double> amp;h, Mat_<double> amp;cdf)
    public static void do1ChnHist(Mat img, Mat mask, Mat h, Mat cdf)
    {
        // C  : for (size_t p = 0; p<img.total(); p  )
        for (var p = 0; p < (Int32)img.Total; p  )
        {
            if (mask(p) > 0)        // ERROR (Issue 1): 'Mat mask - Method name expected' - happens with all Mat types followed by ().
            {
                byte c = img(p);    // ERROR (Issue 1)
                h(c)  = 1.0;        // ERROR (Issue 1)
            }
        }

        CvInvoke.Normalize(h, h, 1, 0, NormType.MinMax);

        cdf(0) = h(0);                      // ERROR (Issue 1)
        for (int j = 1; j < 256; j  )
        {
            cdf(j) = cdf(j - 1)   h(j);     // ERROR (Issue 1)
        }

        CvInvoke.Normalize(cdf, cdf, 1, 0, NormType.MinMax);
    }

    public static void histMatchRGB(Mat src, Mat src_mask, Mat dst, Mat dst_mask)
    {
        double histmatch_epsilon = 0.000001;

        // C  : vector<Mat_<uchar>> chns, chns1;
        //  List<Mat> chns = new List<Mat>(); - this is the main way to convert vector<Mat> chns, chns1 - however itn's not compatible with CvInvoke.Split below
        //  I think I need to declare an IOutputArray below, but not exactly sure how to do this.
        IOutputArray chns = new OutputArray(new Mat(), something??);    // Issue 4.

        CvInvoke.Split(src, chns);
        CvInvoke.Split(dst, chns1);

        for (int i = 0; i < 3; i  )
        {
            // C  : Mat_<double> src_hist = Mat_<double>::zeros(1, 256); etc...
            //     NOTE: here I've assumed 1 channel (last '1' reference in new statements below), as I think we're iterating through RGB
            Mat src_hist = new Mat(1, 256, DepthType.Cv64F, 1);
            Mat dst_hist = new Mat(1, 256, DepthType.Cv64F, 1);
            Mat src_cdf = new Mat(1, 256, DepthType.Cv64F, 1);
            Mat dst_cdf = new Mat(1, 256, DepthType.Cv64F, 1);

            do1ChnHist(chns[i], src_mask, src_hist, src_cdf);   // ERROR (Issue 2): Cannot apply indexing with [] to an expression of type 'Mat'
            do1ChnHist(chns1[i], dst_mask, dst_hist, dst_cdf);  // ERROR(Issue 2)

            byte last = 0;

            Mat lut = new Mat(1, 256, DepthType.Cv8U, 1);
            for (int j = 0; j < src_cdf.Cols; j  )
            {
                double F1j = src_cdf(j);                    // ERROR (Issue 1)

                for (byte k = last; k < dst_cdf.Cols; k  )
                {
                    double F2k = dst_cdf(k);                // ERROR (Issue 1)

                    if (Math.Abs(F2k - F1j) < histmatch_epsilon || F2k > F1j)
                    {
                        lut(j) = k;                         // ERROR (Issue 1)
                        last = k;                   
                        break;
                    }
                }
            }
            
            CvInvoke.LUT(chns[i], lut, chns[i]);            //ERROR(Issue 2)
        }

        Mat res = new Mat();
        CvInvoke.Merge(chns, res);

        res.CopyTo(src);
    }

    internal static void Main(string[] args)
    {
        Mat src = CvInvoke.Imread("e:/test/iO6S1m.png");
        Mat dst = CvInvoke.Imread("e:/test/kfku3m.png");
        Mat mask = new Mat(src.Size, DepthType.Cv8U, 255);

        histMatchRGB(dst, mask, src, mask);
    }
}
 

Спасибо за любую помощь!

Комментарии:

1. Прямые переводы между языками, программными или устными/письменными, почти никогда не будут хорошими. Как правило, в любом случае для языков программирования почти всегда лучше переопределить алгоритм на целевом языке, а не выполнять какие-либо переводы вообще. Это обычно делает полученный код лучше, проще для чтения, понимания и обслуживания (что является важной частью), но также позволяет использовать «стандартную библиотеку» и языковые функции целевого языка, которые могли быть недоступны на исходном языке.

2. Я обнаружил, что обычно более эффективно создавать оболочку clr/cli вокруг существующего кода C , а затем переносить с C на C#. Таким образом, вы можете создать dll из C и использовать ее в C#. Возможно, потребуется 10 минут, но это может быть хорошим введением . codeproject.com/Articles/19354/. … Примечание : Я полностью согласен с @Someprogrammerdude

Ответ №1:

маска(p)

Компилятор интерпретирует это как вызов метода, но mask это объект, поэтому это не работает. Я бы предположил, что вы хотите извлечь элемент в этой позиции. Поскольку Mat класс, похоже, не содержит индексатора, вам, возможно, придется использовать GetData или GetDataPointer преобразовать матрицу в массив, или использовать небезопасный указатель для доступа.

chns[i]

Я бы предположил, что цель состоит в том, чтобы извлечь один канал. Для этого, по-видимому, существует split метод

В целом, вам нужно иметь некоторое представление о том, что делает код, и прочитать документацию, чтобы найти эквивалентные способы выполнения задач.