#c# #c #opencv #emgucv #code-conversion
Вопрос:
Я пытаюсь создать сценарий для сопоставления цветов между двумя изображениями с помощью EmguCV.
Мне удалось найти код, который делает именно то, что я хочу, здесь, однако он написан на C , с которым я не очень хорошо знаком.
Я уверен, что многие из этих вещей являются базовыми проблемами C -> C#, даже если вы не знакомы с EmguCV / OpenCV…
До сих пор я в тупике на следующем (см. Код ниже).
- «маска(p)» — маска имеет тип Mat, и это приводит к ошибке в C#: «ожидается имя метода». Я предполагаю, что код пытается индексировать маску, но не уверен, как это сделать. В коде довольно много таких примеров.
- ‘chns[i]’ — вероятно, аналогично приведенному выше, chns снова относится к типу Mat, и это приводит к ошибке «Невозможно применить индексацию с помощью [] к выражению типа Mat».
- С «маской(p)» выше и другими различными примерами, как только проблема выше будет исправлена, я подозреваю, что возникнет еще одна проблема при сравнении мата с целым числом для перебора — возможно, это просмотр столбцов или строк, я не уверен. (Я имею в виду, например, » если (маска(p) > 0)» )
- С ‘CvInvoke.Разделение(src, chns)» создает ошибку «Не удается преобразовать из» Системы.Коллекции.Generic.List<Emgu.CV.Mat> в Emgu.CV.IOutputArray’. Я предполагаю, что мне нужно определить chns и chns1 для IOutputArray — хотя я не уверен, как это сделать — для объявления IOutputArray с использованием нового OutputArray требуется ссылка IntPtr (возможно, ‘new Mat()’? и родитель — не совсем уверен, что здесь требуется. аренду смотрите ниже.
Я запустил исходный код C через конвертер C в C#, чтобы избавиться от очевидных проблем, и внес столько изменений, сколько смог, чтобы преобразовать вызовы OpenCV в EmguCV, и у меня осталось следующее. Любая помощь в расшифровке оставшихся частей будет принята с величайшей благодарностью.
Дальнейшие предположения, которые я применил:
- При ссылке на » Мат «в именах методов я не думаю, что C# требует, чтобы вы указывали глубину, как вы делаете в C , поэтому я удалил ссылки и, но вместо этого обновил типы глубины при объявлении матов, например» новый мат(1, 256, тип глубины.Cv64F, 1);» (в случае double)
- Обновлены типы переменных, например «uchar» -> «байт»
- Другие преобразования были отменены, кроме очевидных преобразований 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
метод
В целом, вам нужно иметь некоторое представление о том, что делает код, и прочитать документацию, чтобы найти эквивалентные способы выполнения задач.