2013-05-28 5 views
1

저는 OpenCV 및 C++의 초보자입니다. 그러나 이제는이 문제에 대한 해결책을 찾아야합니다. 파란색 배경을 가진 사람의 이미지가 있습니다. 이제 배경을 빼야합니다. 이미지에서 다른 이미지로 바꿉니다. 는 지금은이 문제를 해결하는 두 가지 방법이 있습니다 생각하지만, 내가 더 알고하지 않습니다OpenCV C++에 의해 이미지에서 파란색 배경을 뺍니다

해결 방법 1 :

  1. 변환 이미지 & W
  2. 이로 사용 B로 배경을 감추는 마스크

솔루션이는 :

배경을 찾을 coutour를 사용
  1. ,
  2. 한 다음를 뺍니다.

이미 해결책 1로 구현했지만 그 결과는 예상대로 아닙니다. 다른 더 나은 해결책이 있거나 이미 소스 코드로 구현 한 사람이 있습니까? 귀하의 도움에 감사드립니다.

여기 내 소스 코드를 업데이트, 당신은 배경이 파란색 알고 있다면, 당신은/W을 B로 이미지를 변환하여 귀중한 정보를 잃고 몇 가지 코멘트를 나에게

//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

봅니다 분할. 테두리에 매우 가까운 전경 마스크를 사용하여 cv :: grabCut을 사용하십시오 (예 : 이미지의 4 픽셀을 전경으로 설정). – William

+0

친애하는 William. 더 자세하게 설명해 줄 수 있습니까? 이 상황에서 어떻게 grabCut을 사용할 수 있습니까? 감사합니다 – user2411800

+0

읽기 [이] (http://www.packtpub.com/article/opencv-segmenting-images) 및 시도 [this] (http://stackoverflow.com/questions/14111716/how-to-set-a -mask-image-for-grabcut-in-opencv). – William

답변

0

을주지하시기 바랍니다.

파란색을 착용하지 않은 사람 (적어도 배경색에 매우 가까운 사람은 아님)은 윤곽선을 사용할 필요가 없습니다. 파란색 픽셀을 다른 이미지의 픽셀로 바꿉니다. 이를 달성하기 위해 cvGet2D 및 cvSet2D 함수와 함께 cvScalar 데이터 유형을 사용할 수 있습니다.

편집 : 코드가 원래 설명한 문제보다 훨씬 복잡해 보입니다. 파란색 배경 ("블루 스크린"및 "크로마 키"라고도 함)을 갖는 것은 TV 채널이 뉴스 리더의 배경을 변경하는 데 사용되는 일반적인 방법입니다. 청색을 선택하는 이유는 인간의 피부가 청색 성분에서 덜 우월하다는 것입니다.

청색을 입지 않는다고 가정하면 다음 코드가 작동해야합니다. 당신이 다른 것을 필요로 할 때 알려줘.

//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];} 

    } 
} 

}