RinOS 16 Жалоба Опубликовано March 1, 2012 Всем привет! Делаю отсечение фона с помощью BackgroundSubtractorMOG2, до недавнего времени все отлично работало и качественно отсекало фон. Но столкнулся с проблемой, когда под камерой появляется слишком контрастный (относительно фона) объект, у всего кадра меняется толи цветовой баланс толи экспозиция. В качестве примера привожу картинки: На деле не так экстремально но BackgroundSubtractorMOG2 ужасно глючит. Подскажите как бороться с этой проблемой? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано March 1, 2012 Меняется и то, и другое, но критичной является экспозиция. Критичный параметром для такой съёмки является наличие WDR у камеры. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 2, 2012 Покупка камеры с WDR, это как вариант... Есть какие то способы нормализовать изображение программным способом? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано March 2, 2012 Последнее изображение уже точно не исправить. Если бы изображение было в raw, то нормализовать можно было бы. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 2, 2012 Ну я эти картинки привел что бы понятнее было в чем проблема, на деле все не так запущено. Максимум как предпоследняя картинка. Видео обычное avi c кодеком mjpg. Пока не придумал как нормализовать изображение... сложность возникает даже с запросом к гуглу... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано March 2, 2012 Я бы решал эту проблему аппаратно - настройками камеры или её заменой. А так... Можно выровнять яркость по гистограмме (cvEqualizeHist). Но там надо с серым изображением работать. Если нужно цветное, то конвертировать в YUV или HSV, применить cvEqualizeHist к каналу с яркостью и снова конвертировать в RGB. Однако, если изображение чем-то было пережато, могут появиться нежелательные эффекты. Надо пробовать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 2, 2012 Можно выровнять яркость по гистограмме (cvEqualizeHist). Но там надо с серым изображением работать. Если нужно цветное, то конвертировать в YUV или HSV, применить cvEqualizeHist к каналу с яркостью и снова конвертировать в RGB. Да, видел пост в котором советовали использовать cvEqualizeHist, пробовал и с YUV и HSV. Сначала cvSplit, потом пробовал со всеми слоями и комбинировал) (в общем по всякому тестил) cvEqualizeHist, потом снова собирал cvMerge и передавал полученную картинку BackgroundSubtractorMOG2, но результат не лучше а порой даже хуже. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 2, 2012 Гонзалез с Вудсом рекомендуют выровнять гистограмму только для S и V компонентов, а H не трогать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано March 2, 2012 У меня авто экспозиция меняла цвет с красного на зелёный. Так что считаю решается отключением в драйвере или заменой камеры. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 2, 2012 Вспомнился еще способ выравнивания освещения: Пропускаем изображение через очень низкочастотный фильтр, тем самым получаем очень размытое изображение. Затем это изображение, умноженное на коэффициент, вычитаем из нашего изображения. Хотя, если информация о цвете потеряна, то тут уже ничего не сделаешь. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 5, 2012 Пропускаем изображение через очень низкочастотный фильтр это как)? можно подробнее... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано March 5, 2012 просто гауссом размыть. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 5, 2012 Долгими поисками по гуглу нашел одну замечательную функцию: 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. Тем самым функция станет чуть более адаптивной. 2 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 5, 2012 По поводу MSE (см. getPSNR ): http://opencv.itseez.com/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.html Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано March 7, 2012 Встретил такую штуку в 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 ); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах