Background subtraction

David8·2022년 10월 12일
0

컴퓨터비전

목록 보기
11/17

기초

  1. video segmentation: 동영상을 여러개의 영역으로 나누는 것
  2. 종류
    1. chroma-keying(두개 영상 합성)
    2. surveillance camera(감시카메라)
  3. 알고리즘

background subtraction

  1. 정의: 영상에서 background 찾는 것 --> 배경 자체를 위해서가 아니라 물체를 감지하기 위한 과정

  2. 과정

    1. f(x,y,t): current frame, b(x,y,t): background 가정
    2. 물체 인식
    3. 유의점
      1. 두 영상은 동일한 위치에서 촬영되어야 함
      2. 조명의 차이가 크지x
  3. 유의사항 --> background를 무엇으로 정의할지 중요

    1. 갑작스럽거나 점진적인 조명의 변화 다루어야함
    2. 반복적인 동작
      1. 나뭇잎
      2. 파도
    3. 오랜 시간에 걸쳐진 변화
      1. 분실물 가방
      2. 주차 차량
  4. background estimation

    1. mean filter

      1. background = 이전 n frame의 평균

        첫번째: t라는 시점 부터 n frame, 두번째: 처음 시작부터 n frame

    2. median

    3. GMM(Gaussian mixture model)

      1. 과정
        1. 몇개의 가우시안을 사용할지 결정
        2. 배경영상이 주어진 경우, 각각의 가우시안 평균과 표준편차를 토대로 𝑝(𝐴|𝐵) 계산
          1. A: 특정한 value, B: background
        3. 𝑝(𝐴|𝐵)를 바탕으로 𝑝(𝐵|𝐴)를 구해서 특정한 value가 픽셀 분포가 많은 곳에 있으면 background로, 픽셀 분포가 적은 곳에 있으면 foreground로 인식
  5. 코드

    Generating average image

int main() {
  VideoCapture capture("background.mp4"); 
  Mat image, sum, avg;
  int cnt = 2;
  
  capture >> avg;
  while (true) {
    if (!capture.read(image)) break; 
    add(image / cnt, avg*(cnt - 1) / cnt, avg);
    
    imshow("avg", avg); 
    cnt++;
    waitKey(33);
	} 
}

using absdiff

int main() {
  VideoCapture capture("background.mp4");
  Mat background, image, gray, result, foregroundMask, foregroundImg;
  
  //set the first frame as background
  capture >> background;
  cvtColor(background, background, CV_BGR2GRAY);
  
  while (true) {
    if (capture.grab() == 0) break; 
    capture.retrieve(image); 
    cvtColor(image, gray, CV_BGR2GRAY);
    
    absdiff(background, gray, foregroundMask);
    threshold(foregroundMask, foregroundMask, 50, 255, CV_THRESH_BINARY); 
    foregroundMask.copyTo(foregroundImg);
    gray.copyTo(foregroundImg, foregroundMask);

    imshow("foregroundImg", foregroundImg); 
    imshow("foregroundMask", foregroundMask); 
    imshow("background", background);
    

    waitKey(33); 
  }
}

mog2(mix of gausiian)

int main() {
  Ptr<BackgroundSubtractor> bg_model = createBackgroundSubtractorMOG2(); Mat image, foregroundMask, backgroundImg, foregroundImg;
  VideoCapture cap("background.mp4");
  
  while (true) {
  cap >> image;
  resize(image, image, Size(640, 480));
  
  if (foregroundMask.empty()) 
  	foregroundMask.create(image.size(), image.type());
  // image: Next video frame. Floating point frame will be used without scaling and //should be in range [0,255]. 
  // foregroundMask: The output foreground mask as an 8-bit binary image.
  bg_model->apply(image, foregroundMask);
  GaussianBlur(foregroundMask, foregroundMask, Size(11, 11), 3.5, 3.5);
  threshold(foregroundMask, foregroundMask, 10, 255, THRESH_BINARY); 
  foregroundImg = Scalar::all(0);
  image.copyTo(foregroundImg, foregroundMask);
  
  // backgroundImg: The output background image. 
  bg_model->getBackgroundImage(backgroundImg);
  imshow("foreground mask", foregroundMask); 
  imshow("foreground image", foregroundImg);
  
  if (!backgroundImg.empty()) {
  	imshow("mean background image", backgroundImg); 
  }
  
  waitKey(33); 
  }
}

morphological operation(모폴로지 연산-형태학적 연산)

  1. 배경 영상과 현재 영상의 차이를 토대로 객체 영역 추출 가능 --> 하나의 객체를 많은 물체가 존재하는 것처럼 인식 할 수 있으므로 후처리 작업(morphological operation)이 필요

    1. morphological operation을 사용하면 조각난 물체 하나로 합칠 수 있음
    2. binary image 가공 절차임
  2. 종류

    1. erosion(침식)
      1. 영상 내 b필터로 스캐닝 -> b가 온전히 포함된 경우만 남겨두는 것(해당 픽셀 1로 설정)
        1. 물체를 축소시키거나 얇게 만든 효과 있음
        2. 교집합, &의 의미
    2. dilation(팽창)
      1. structure elemet 이동(스캐닝) -> 일부분이라도 물체 A에 포함된 영역 찾는 것
        1. 빈틈 없애줌
        2. 합집합, or의 의미
  3. opening & closing

    1. 침식과 팽창 중 어느 연산을 먼저 수행하였느냐의 차이
    2. opening(열림 연산)
      1. 침식 -> 팽창
      2. 얅은 부분들 쪼개지고, 조그만한 점 제거, 윤곽선 부드러워짐
    3. closing(닫힘 연산)
      1. 팽창 -> 침식
      2. 조그만한 구멍 제거, 윤곽선 부드러워짐
  4. 코드

    Counting the number of objects

int main() {
  Mat gray = imread("contours.png", 0);
  Mat result;
  threshold(gray, result, 230, 255, THRESH_BINARY_INV);
  vector<vector<Point>> contours;
  vector<Vec4i>hierarchy;
  findContours(result, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // 개수 찾는 함수
  
  putText(result, format("contour count: %d", contours.size()), Point(50, 80), FONT_HERSHEY_SIMPLEX, 1, Scalar(12 8), 4); // contours.size(): 개수
  
  imshow("contours", result);
  waitKey(0); 
}

Counting the number of objects(겹치는 것들)

int main() {
  Mat gray = imread("contours.png", 0);
  Mat result;
  threshold(gray, result, 180, 255, THRESH_BINARY_INV); vector<vector<Point>> contours; vector<Vec4i>hierarchy;
  findContours(result, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
  
  //defining bounding rectangle vector<Rect> boundRect(contours.size()); 
  for (int i = 0; i < contours.size(); i++)
  	boundRect[i] = boundingRect(Mat(contours[i])); 
  //draw rectangles on the contours
  for (int i = 0; i < contours.size(); i++)
  	rectangle(result, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 0, 255), 2, 8, 0);
  imshow("contours", result);
  waitKey(0); 
}

Erosion and dilation

int main(){
  Mat image, erosion, dilation;
  Mat element = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
  //Other options:MORPH_RECT, MORPH_CROSS
  
  image = imread(“water_coins.jpg", 0); 
  threshold(image, image, 128, 255, THRESH_BINARY);
  
  erode(image, erosion, element); 
  dilate(image, dilation, element);
  
  imshow("Binary image", image); 
  imshow("Erosion", erosion); 
  imshow("Dilation", dilation); 
	waitKey(0);
}  

opening and closing

int main(){
  Mat image, opening, closing, element; 
  image = imread(“water_coins.jpg", 0);

  threshold(image, image, 128, 25, THRESH_BINARY);
  element = getStructuringElement(MORPH_ELLIPSE, Size(7, 7));

  morphologyEx(image, closing, MORPH_CLOSE, element); 
  morphologyEx(image, opening, MORPH_OPEN, element);

  imshow("Binary image", image); 
  imshow("opening", opening); 
  imshow("closing", closing); 
  waitKey(0);
}

0개의 댓글