Перейти к содержимому
Compvision.ru
RinOS

Проблема с авто-экспозицией

Recommended Posts

Всем привет!

Делаю отсечение фона с помощью BackgroundSubtractorMOG2, до недавнего времени все отлично работало и качественно отсекало фон.

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

В качестве примера привожу картинки:

0287fb7790ebt.jpg 622e998bbbeet.jpg 1a6ed57ee54at.jpg b15353966492t.jpg dbe2b272378bt.jpg

На деле не так экстремально но BackgroundSubtractorMOG2 ужасно глючит.

Подскажите как бороться с этой проблемой?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Меняется и то, и другое, но критичной является экспозиция. Критичный параметром для такой съёмки является наличие WDR у камеры.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Покупка камеры с WDR, это как вариант...

Есть какие то способы нормализовать изображение программным способом?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Последнее изображение уже точно не исправить. Если бы изображение было в raw, то нормализовать можно было бы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну я эти картинки привел что бы понятнее было в чем проблема, на деле все не так запущено.

Максимум как предпоследняя картинка.

Видео обычное avi c кодеком mjpg.

Пока не придумал как нормализовать изображение... сложность возникает даже с запросом к гуглу...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я бы решал эту проблему аппаратно - настройками камеры или её заменой. А так...

Можно выровнять яркость по гистограмме (cvEqualizeHist). Но там надо с серым изображением работать. Если нужно цветное, то конвертировать в YUV или HSV, применить cvEqualizeHist к каналу с яркостью и снова конвертировать в RGB.

Однако, если изображение чем-то было пережато, могут появиться нежелательные эффекты.

Надо пробовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Можно выровнять яркость по гистограмме (cvEqualizeHist). Но там надо с серым изображением работать. Если нужно цветное, то конвертировать в YUV или HSV, применить cvEqualizeHist к каналу с яркостью и снова конвертировать в RGB.

Да, видел пост в котором советовали использовать cvEqualizeHist, пробовал и с YUV и HSV. Сначала cvSplit, потом пробовал со всеми слоями и комбинировал) (в общем по всякому тестил) cvEqualizeHist, потом снова собирал cvMerge и передавал полученную картинку BackgroundSubtractorMOG2, но результат не лучше а порой даже хуже.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Гонзалез с Вудсом рекомендуют выровнять гистограмму только для S и V компонентов, а H не трогать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

У меня авто экспозиция меняла цвет с красного на зелёный. Так что считаю решается отключением в драйвере или заменой камеры.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вспомнился еще способ выравнивания освещения:

Пропускаем изображение через очень низкочастотный фильтр, тем самым получаем очень размытое изображение.

Затем это изображение, умноженное на коэффициент, вычитаем из нашего изображения.

Хотя, если информация о цвете потеряна, то тут уже ничего не сделаешь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Пропускаем изображение через очень низкочастотный фильтр

это как)? можно подробнее...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Долгими поисками по гуглу нашел одну замечательную функцию:


CVStatus cvNormalizeIllum(IplImage *img, const float destMean, const float destMse)

{

    uchar* src_data;

    float* dst_data;

    CvRect src_roi;

    int width_step, width, height, roi_size, img_index, data_index;

    CvSize data_size;

    float temp_float, mse_ratio;

    int i, x, y;

    float A11=0, A12=0, A13=0, A21=0, A22=0, A23=0, A31=0, A32=0, A33=0;

    float I_point;

    float B1=0, B2 = 0, B3 = 0;

    float Det;

    float B11, B12, B13, B22, B23, B33;

    float A1, A2, A3;

    float cal_mean, cal_mse;


    // check arguments

    if (destMean < 0.0f || destMse < 0.0f)

        return CV_StsBadArg;


    // check image

    if (img->depth != IPL_DEPTH_8U)

        return CV_BadDepth;

    if (img->nChannels != 1)

        return CV_BadNumChannels;


    // Get raw data

    cvGetRawData(img, (uchar **) &src_data, &width_step, &data_size);

    src_roi = cvGetImageROI(img);


    width = data_size.width;

    height = data_size.height;

    roi_size = width * height;

    dst_data = (float *)cvAlloc(roi_size * sizeof(float));


    //1. Caculate the A'A

    for(y=0; y<height; y++)

    {

        for(x=0; x<width; x++)

        {

            A11 += x * x;

            A12 += x * y;

            A13 += x;

            A22 += y * y;

            A23 += y;

        }

    }

    A33 = (float)roi_size;


    //2. Caculate the A'B

    img_index = 0;

    for(y=0; y<height; y++)

    {

        for(x=0; x<width; x++)

        {

            I_point = (float)src_data[img_index + x];

            B1 += x * I_point;

            B2 += y * I_point;

            B3 += I_point;

        }

        img_index += width_step;

    }


    //3. Caculate the inverse matrix (A'A)

    Det = - A11*A22*A33 + A11*A23*A23 + A12*A12*A33 - 2*A12*A13*A23 + A13*A13*A22;

    if(Det == 0)

        return CV_StsError;

    B11 =  - (A22*A33 - A23*A23) / Det;

    B12 = (A12*A33 - A13*A23) / Det;

    B13 = - (A12*A23 - A13*A22) / Det;

    B22 = - (A11*A33 - A13*A13) / Det;

    B23 = - ( - A11*A23 + A12*A13) / Det;

    B33 = ( - A11*A22+A12*A12) / Det;


    //4. Solve equations and find a1, a2, a3

    A1 = B11 * B1 + B12 * B2 + B13 * B3;

    A2 = B12 * B1 + B22 * B2 + B23 * B3;

    A3 = B13 * B1 + B23 * B2 + B33 * B3;


    //5. Brightness correction

    cal_mean = 0;

    data_index = 0;

    img_index = 0;

    for (y=0; y<height; y++)

    {

        for (x=0; x<width; x++)

        {

            I_point = (float)src_data[img_index + x] - (A1 * x + A2 * y + A3);

            dst_data[data_index] = I_point;

            data_index ++;

            cal_mean += I_point;

        }

        img_index += width_step;

    }

    cal_mean /= (width * height);


    // MSE Caculation

    cal_mse = 0;

    for( i=0; i<roi_size; i++)

    {

        temp_float = dst_data[i] - cal_mean;

        cal_mse += temp_float * temp_float;

    }

    cal_mse = (float)sqrt( cal_mse / roi_size );


    // MSE normalization and write back to image buffer

    if (cal_mse == 0) {

        data_index = 0;

        img_index = 0;

        for (y=0; y<height; y++)

        {

            for (x=0; x<width; x++)

            {

                src_data[img_index + x] = (unsigned char)destMean;

            }

            img_index += width_step;

        }

    }

    else {

        mse_ratio = destMse / cal_mse;

        data_index = 0;

        img_index = 0;

        for (y=0; y<height; y++)

        {

            for (x=0; x<width; x++)

            {

                temp_float = (dst_data[data_index] - cal_mean) * mse_ratio + destMean;

                data_index ++;

                if(temp_float > 255.0f)

                    src_data[img_index + x] = 255;

                else if (temp_float < 0.0f)

                    src_data[img_index + x] = 0;

                else

                    src_data[img_index + x] = (uchar)(temp_float + 0.5f);

            }

            img_index += width_step;

        }

    }


    cvFree((void**)&dst_data);


    return CV_StsOk;

}

У нее есть две переменные destMean и destMse.

destMean - destation mean value of the MSE normalization

destMse - destation MSE of the MSE normalization

Что бы не задавать их жестко хотелось бы как ни будь вычислить эти два значения, на основании background image взятого у BackgroundSubtractorMOG2. Тем самым функция станет чуть более адаптивной.

  • Like 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Весь функционал opencv_stitching мне не нужен, нужно лишь выравнивание экспозиции относительно первой (главной) картинки.

Документации по ExposureCompensator очень мало. Особенно не понятно какие числа должны быть в corners

compensator->feed( corners, images, mask )

Пока что делаю так но эффекта не замечаю. Хотя отрабатывает функция без ошибок.


void Compensator::feed(Mat &etalon, Mat &fix)

{

    pt0.x = 1; //???

    pt0.y = 1; //???


    pt1.x = frame.rows - 1; //???

    pt1.y = frame.cols - 1; //???


    corners.push_back( pt0 );

    corners.push_back( pt1 );


    m0.create( frame.rows, frame.cols, CV_8U );

    m0.setTo( cv::Scalar::all(255) );


    m1.create( frame.rows, frame.cols, CV_8U );

    m1.setTo( cv::Scalar::all(255) );


    mask.push_back( m0 );

    mask.push_back( m1 );


    images.push_back( etalon );

    images.push_back( fix );


    compensator->feed( corners, images, mask );

    compensator->apply( images.size() - 1, pt0, fix, m0 );

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×