정의: 영상에서 background 찾는 것 --> 배경 자체를 위해서가 아니라 물체를 감지하기 위한 과정
과정
유의사항 --> background를 무엇으로 정의할지 중요
background estimation
mean filter
첫번째: t라는 시점 부터 n frame, 두번째: 처음 시작부터 n frame
median
GMM(Gaussian mixture model)
코드
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)이 필요
종류
opening & closing
코드
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);
}