2013-06-10 3 views
3

Я вижу, есть похожие вопросы к этому, но не отвечайте на то, что я прошу, поэтому вот мой вопрос.Различные пиксельные значения в MATLAB и C++ с OpenCV

В C++ с OpenCV Я запускаю код, который я приведу ниже, и возвращает среднее значение пикселя 6.32. Однако, когда я открываю изображение и использую среднюю функцию в MATLAB, он возвращает среднюю интенсивность пикселя приблизительно 6.92ish. Как вы можете видеть, я конвертирую значения OpenCV в double, чтобы попытаться облегчить эту проблему, и обнаружил, что openCV загружает изображение в виде набора целых чисел, тогда как MATLAB загружает изображение как десятичные значения, которые приблизительно, но не совсем такие же, как целые числа , Итак, мой вопрос, новичок в кодировании, что правильно? Я предполагаю, что MATLAB возвращает более точные значения, и если это так, я хотел бы знать, есть ли способ загрузить изображения таким же образом, чтобы избежать расхождения.

Спасибо, код ниже

Mat img = imread("Cells2.tif"); 
cv::cvtColor(img, img, CV_BGR2GRAY); 
cv::imshow("stuff",img); 
Mat dst; 
if(img.channels() == 3) 
{ 
    img.convertTo(dst, CV_64FC1); 
} 
else if (img.channels() == 1) 
{ 
    img.convertTo(dst, CV_64FC1); 
} 
cv::imshow("output",dst/255); 
int NumPixels = img.total(); 


double avg; 
double c = 0; 
double std; 
    for(int y = 0; y < dst.cols; y++) 
    { 

     for(int x = 0; x < dst.rows; x++) 
     { 
      c+=dst.at<double>(x,y)*255; 
     } 
    } 

avg = c/NumPixels; 
cout << "asfa = " << c << endl; 
double deviation; 

double var; 
double z = 0; 
double q; 
    //for(int a = 0; a<= img.cols; a++) 
for(int y = 0; y< dst.cols; y++) 
    { 
     //for(int b = 0; b<= dst.rows; b++) 
     for(int x = 0; x< dst.rows; x++) 
     { 
      q=dst.at<double>(x,y); 

      deviation = q - avg; 
      z = z + pow(deviation,2); 
      //cout << "q = " << q << endl; 
     } 

    } 

var = z/(NumPixels); 
std = sqrt(var); 
cv::Scalar avgPixel = cv::mean(dst); 

cout << "Avg Value = " << avg << endl; 
cout << "StdDev = " << std << endl; 
cout << "AvgPixel =" << avgPixel; 

cvWaitKey(0); 
return 0; 

}

+0

MATLAB может обнаруживать диапазон значений пикселей в предположении, самая высокая значение составляет 100% яркости. Если самое яркое значение составляет около 233, это объясняет разницу. –

+0

Есть ли способ учета и прекращения несоответствия? – VeniVici

+0

Можете ли вы показать свой код Matlab для вычисления средней интенсивности пикселей изображения? – Alexey

ответ

5

В соответствии с вашими комментариями изображение, похоже, хранится с 16-разрядной глубиной. MATLAB загружает изображение TIFF как есть, тогда как по умолчанию OpenCV загрузит изображения как 8-битные. Это может объяснить разницу в точности, которую вы видите.

Используйте следующее, чтобы открыть изображение в OpenCV:

cv::Mat img = cv::imread("file.tif", cv::IMREAD_ANYDEPTH|cv::IMREAD_ANYCOLOR); 

В MATLAB, это просто:

img = imread('file.tif'); 

Далее вам нужно знать о данных типа вы работаете с. В OpenCV его CV_16U, в MATLAB его uint16. Поэтому вам необходимо соответствующим образом преобразовывать типы.

Например, в MATLAB:

img2 = double(img) ./ double(intmax('uint16')); 

бы преобразовать его в double изображения со значениями в диапазоне [0,1]

+0

вы можете сделать аналогичное преобразование в OpenCV, используя: 'img.convertTo (img2, CV_64F, 1.0/65535);' – Amro

+0

YESSSSS благодарю вас так много, что это работало именно на том, что проблема конверсии прямо там. Большое спасибо за это. – VeniVici

0
  1. Вы преобразующее изображение, если определенные условия выполняются, то это может изменить некоторые значения цветов в то время как MATLAB может выбрать, чтобы не преобразовывать изображения, но используйте необработанное изображение
  2. цвета в основном представлены в шестнадцатеричном формате с популярными реализациями в формате 0xAARRGGBB или 0xRRGGBBAA, поэтому будут выполняться 32-разрядные целые числа (без знака/подписи не имеет значения, шестнадцатеричное значение остается тем же), создать 64-битную переменную, добавить все 32-битные переменные вместе, а затем разделить на количество пикселей, это даст вам довольно точный результат (для изображений до 16384 на 16384 пикселя (где 32-битное значение представляет цвет одного пикселя), если оно больше, то для 64-битного целого будет недостаточно).

    long long total = 0; 
    long long divisor = image.width * image.height; 
    for(int x = 0; x < image.width; ++x) 
    { 
        for(int y = 0; x < image.height; ++x) 
        { 
         total += image.at(x,y).color; 
        } 
    } 
    double avg = total/divisor; 
    std::cout << "Average color value: " << avg << std::endl; 
    
+0

Нет. Вам нужно обрабатывать цветные плоскости отдельно, но в этом методе они мешают друг другу (оба они переносятся во время добавления, а часть фракции во время деления попадает в другие цветные плоскости и повреждает результат) –

+0

Да, это возвращалось получивший результат после того, как я попытался отредактировать его, чтобы он запустился. Я ценю помощь в любом случае, но это бесполезно :( – VeniVici

+0

, может быть, если вы скажете, что было результатом или где оно пошло не так, я мог бы отредактировать его и исправить? :) Я здесь, чтобы помочь человеку ^.^ –

0

При загрузке изображения, вы должны использовать подобные методы в обеих средах (MATLAB и OpenCV), чтобы избежать возможных переходов, которые могут быть сделаны по умолчанию в любой среде.

0

Не знаете, какую сложность у вас есть со средним значением в Matlab по сравнению с OpenCV. Если я правильно понял ваш вопрос, ваша цель - реализовать mean(image(:)) Matlab в OpenCV. Например, в Matlab выполнить следующие действия:

>> image = imread('sheep.jpg') 
>> avg = mean(image(:)) 

ans = 

    119.8210 

Вот как сделать то же самое в OpenCV:

Mat image = imread("sheep.jpg"); 
Scalar avg_pixel; 
avg_pixel = mean(image); 
float avg = 0; 
cout << "mean pixel (RGB): " << avg_pixel << endl; 

for(int i; i<image.channels(); ++i) { 
    avg = avg + avg_pixel[i]; 
} 
avg = avg/image.channels(); 
cout << "mean, that's equivalent to mean(image(:)) in Matlab: " << avg << endl; 

OpenCV консольный вывод:

mean pixel (RGB): [77.4377, 154.43, 127.596, 0] 
mean, that's equivalent to mean(image(:)) in Matlab: 119.821 

Таким образом, результаты одинаковы в Matlab и OpenCV.

Последующие действия У вас есть проблемы с кодом.

  • OpenCV хранит данные, отличные от Matlab. Посмотрите на this answer для приблизительного объяснения того, как получить доступ к пикселю в OpenCV.Например:

    // NOT a correct way to access a pixel in CV_F32C3 type image 
    double pixel = image.at<double>(x,y); 
    
    //The correct way (where the pixel value is stored in a vector) 
    // Note that Vec3d is defined as: typedef Vec<double, 3> Vec3d; 
    Vec3d pixel = image.at<Vec3d>(x, y); 
    
  • Другая ошибка я нашел

    if(img.channels() == 3) 
    { 
        img.convertTo(dst, CV_64FC1); //should be CV_64FC3, instead of CV_64FC1 
    } 
    

Доступ Mat элементов может привести к путанице. Я предлагаю получить книгу по OpenCV для начала работы, например this one, и читать OpenCV tutorials and documentation. Надеюсь это поможет.

+0

Бах поблагодарить вас за то, что вы нашли эти глупые ошибки. Однако изображение имеет оттенки серого, что хорошо и хорошо, ваш код просто выплюнет вектор 6.321, который * 255 равно 1612 (это и есть то, что я на самом деле плохо кодировал для петель). Однако в MATLAB эта же картина дает значение 1776. Я вижу, что для вашей фотографии она дала то же среднее значение. возвращая такое другое значение? Это оттенок серого .tif, если это помогает. – VeniVici

+0

Я только что попытался с помощью lena.bmp и поместил его в оттенки серого в Matlab и OpenCV, а в openCV - мой рукописный код и cv :: mean (img) вернул значение из 95.6564, где MATLAB возвращает 96,5 ... Я понятия не имею, ха-ха. – VeniVici

+0

Итак, вы сначала конвертируете изображение в оттенки серого, а затем вычисляете его среднее значение? – Alexey

Смежные вопросы