2013-05-28 3 views
1

Я новичок в OpenCV и C++, но теперь я должен найти решение этой проблемы: У меня есть изображение человека с синим фоном, теперь мне приходится вычитать фон из изображения, затем замените его другим изображением. Теперь я думаю, что есть 2 пути решения этой проблемы, но я не знаю, что лучше:Вычитаем синий фон с изображения OpenCV C++

Решение 1:

  1. Преобразовать изображение B & W
  2. Используйте его как маску для вычитания фона.

Решение 2:

  1. Использование coutour найти фон,
  2. , а затем вычесть его.

Я уже реализовал решение 1, но результат не такой, как я ожидаю. Знаете ли вы, что есть другое лучшее решение, или кто-то уже реализует его как исходный код? Поблагодарите вашу помощь.

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

//Get the image with person 
cv::Mat imgRBG = imread("test.jpg"); 
//Convert this image to grayscale 
cv::Mat imgGray = imread("test.jpg",CV_LOAD_IMAGE_GRAYSCALE); 
//Get the background from image 
cv::Mat background = imread("paris.jpg"); 

cv::Mat imgB, imgW; 
//Image with black background but inside have some area black 
threshold(imgGray, imgB, 200, 255, CV_THRESH_BINARY_INV); 

cv::Mat imgTemp; 
cv::Mat maskB, maskW; 
cv::Mat imgDisplayB, imgDisplayW; 
cv::Mat imgDisplay1, imgDisplay2, imgResult;  

//Copy image with black background, overide the original image 
//Now imgTemp has black background wrap the human image, and inside the person, if there're some white area, they will be replace by black area 
imgRBG.copyTo(imgTemp, imgB); 

//Now replace the black background with white color 
cv::floodFill(imgTemp, cv::Point(imgTemp.cols -10 ,10), cv::Scalar(255.0, 255.0, 255.0)); 
cv::floodFill(imgTemp, cv::Point(10,10), cv::Scalar(255.0, 255.0, 255.0)); 
cv::floodFill(imgTemp, cv::Point(10,imgTemp.rows -10), cv::Scalar(255.0, 255.0, 255.0)); 
cv::floodFill(imgTemp, cv::Point(imgTemp.cols -10,imgTemp.rows -10), cv::Scalar(255.0, 255.0, 255.0)); 

//Convert to grayscale 
cvtColor(imgTemp,imgGray,CV_RGB2GRAY); 

//Convert to B&W image, now background is black, other is white 
threshold(imgGray, maskB, 200, 255, CV_THRESH_BINARY_INV); 

//Convert to B&W image, now background is white, other is black 
threshold(imgGray, maskW, 200, 255, CV_THRESH_BINARY); 

//Replace background of image by the black mask 
imgRBG.copyTo(imgDisplayB, maskB); 

//Clone the background image 
cv::Mat overlay = background.clone(); 

//Create ROI 
cv::Mat overlayROI = overlay(cv::Rect(0,0,imgDisplayB.cols,imgDisplayB.rows)); 

//Replace the area which will be human image by white color 
overlayROI.copyTo(imgResult, maskW); 

//Add the person image 
cv::addWeighted(imgResult,1,imgDisplayB,1,0.0,imgResult); 

imshow("Image Result", imgResult); 


waitKey(); 

return 0; 
+0

сегментации Try. Используйте cv :: grabCut с маской переднего плана, очень близкой к границам (например, установите 4 угловых пикселя изображения в качестве передних). – William

+0

Дорогой Уильям. Можете ли вы подробнее описать? Как я могу использовать grabCut в этой ситуации? Спасибо – user2411800

+0

Прочтите [это] (http://www.packtpub.com/article/opencv-segmenting-images) и попробуйте [this] (http://stackoverflow.com/questions/14111716/how-to-set-a -mask-изображение-в-grabcut-в-OpenCV). – William

ответ

0

Если вы знаете, что фон синий, вы теряете ценную информацию путем преобразования изображения в B/W.

Если человек не носит синий (по крайней мере, не тот, который находится очень близко к цвету фона), вам не нужно использовать контуры. просто замените синие пиксели пикселями от другого изображения. Для этого вы можете использовать тип данных cvScalar с функциями cvGet2D и cvSet2D.

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

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

//Read the image with person 
IplImage* imgPerson = cvLoadImage("person.jpg"); 
//Read the image with background 
IplImage* imgBackground = cvLoadImage("paris.jpg"); 

// assume that the blue background is quite even 
// here is a possible range of pixel values 
// note that I did not use all of them :-) 
unsigned char backgroundRedMin = 0; 
unsigned char backgroundRedMax = 10; 
unsigned char backgroundGreenMin = 0; 
unsigned char backgroundGreenMax = 10; 
unsigned char backgroundBlueMin = 245; 
unsigned char backgroundBlueMax = 255; 

// for simplicity, I assume that both images are of the same resolution 
// run a loop to replace pixels 
for (int i=0; i<imgPerson->width; i++) 
{ 
    for (int j=0; j< imgPerson->height; j++) 
    { 
     CvScalar currentPixel = cvGet2D(imgPerson, j, i); 
     // compare the RGB values of the pixel, with the range 
     if (curEdgePixel.val[0] > backgroundBlueMin && curEdgePixel.val[1] < 
      backgroundGreenMax && curEdgePixel.val[2] < backgroundRedMax) 
      { 
      // copy the corresponding pixel from background 
      CvScalar currentBackgroundPixel = cvGet2D(imgBackground, j, i); 
      cvSet2D(imgPerson, j, i, currentBackgroundPixel); 
      } 
     } 
    } 


imshow("Image Result", imgPerson); 

waitKey(); 

return 0; 
+0

Спасибо за вашу помощь, я уже обновил свой исходный код, не могли бы вы дать мне несколько комментариев? – user2411800

+0

Готово. Дайте мне знать, если я не отвечу на ваш вопрос. – Totoro

+1

Если ваш фон не синий или неравномерный, GrabCut - лучший выбор. – Totoro

0

Проверить этот проект

https://sourceforge.net/projects/cvchromakey

void chromakey(const Mat under, const Mat over, Mat *dst, const Scalar& color) { 

// Create the destination matrix 
*dst = Mat(under.rows,under.cols,CV_8UC3); 

for(int y=0; y<under.rows; y++) { 
    for(int x=0; x<under.cols; x++) { 

    if (over.at<Vec3b>(y,x)[0] >= red_l && over.at<Vec3b>(y,x)[0] <= red_h && over.at<Vec3b>(y,x)[1] >= green_l && over.at<Vec3b>(y,x)[1] <= green_h && over.at<Vec3b>(y,x)[2] >= blue_l && over.at<Vec3b>(y,x)[2] <= blue_h) 
     { 
       dst->at<Vec3b>(y,x)[0]= under.at<Vec3b>(y,x)[0]; 
       dst->at<Vec3b>(y,x)[1]= under.at<Vec3b>(y,x)[1]; 
       dst->at<Vec3b>(y,x)[2]= under.at<Vec3b>(y,x)[2];} 
      else{ 
       dst->at<Vec3b>(y,x)[0]= over.at<Vec3b>(y,x)[0]; 
       dst->at<Vec3b>(y,x)[1]= over.at<Vec3b>(y,x)[1]; 
       dst->at<Vec3b>(y,x)[2]= over.at<Vec3b>(y,x)[2];} 

    } 
} 

}

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