Created
June 30, 2011 04:08
-
-
Save t-abe/1055619 to your computer and use it in GitHub Desktop.
interactive grabcut application using OpenCV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <useopencv.h> | |
#include <string> | |
#include <vector> | |
#include <iostream> | |
class InteractiveGrabcut { | |
cv::Mat src; | |
cv::Mat fgd, bgd; | |
bool ldrag, rdrag; | |
std::string name; | |
public: | |
cv::Mat mask; | |
//cv::Rect rect; | |
cv::Point lstart, rstart; | |
cv::Scalar fg_color, bg_color; | |
InteractiveGrabcut() | |
: src(), mask(), fgd(), bgd(), | |
ldrag(false), rdrag(false), name("igc"), | |
fg_color(0, 0, 255), bg_color(255, 0, 0) | |
{}; | |
InteractiveGrabcut(const cv::Mat& src_) | |
: src(src_), mask(), fgd(), bgd(), | |
ldrag(false), rdrag(false), name("igc"), fg_color(0, 0, 255), bg_color(255, 0, 0) | |
{ | |
mask = cv::Mat::ones(src_.size(), CV_8U) * cv::GC_PR_BGD; | |
}; | |
void prepareWindow(const std::string name){ | |
this->name = name; | |
cv::namedWindow(name); | |
cv::setMouseCallback(name, events, this); | |
}; | |
static void events( int e, int x, int y, int flags, void* s ){ | |
InteractiveGrabcut* self = (InteractiveGrabcut*)s; | |
cv::Point pt(x, y); | |
switch(e) { | |
case CV_EVENT_LBUTTONDOWN: | |
self->ldrag = true; | |
self->lstart = pt; | |
break; | |
case CV_EVENT_LBUTTONUP: | |
self->ldrag = false; | |
break; | |
case CV_EVENT_RBUTTONDOWN: | |
self->rdrag = true; | |
self->rstart = pt; | |
break; | |
case CV_EVENT_RBUTTONUP: | |
self->rdrag = false; | |
break; | |
case CV_EVENT_MOUSEMOVE: | |
if(self->ldrag) { | |
cv::line(self->mask, self->lstart, pt, cv::Scalar(cv::GC_FGD), 1); | |
self->lstart = pt; | |
} | |
else if(self->rdrag) { | |
cv::line(self->mask, self->rstart, pt, cv::Scalar(cv::GC_BGD), 1); | |
self->rstart = pt; | |
} | |
break; | |
default: | |
break; | |
}; | |
}; | |
void show(){ | |
cv::Mat scribbled_src = src.clone(); | |
const float alpha = 0.7f; | |
for(int y=0; y < mask.rows; y++){ | |
for(int x=0; x < mask.cols; x++){ | |
if(mask.at<uchar>(y, x) == cv::GC_FGD) { | |
cv::circle(scribbled_src, cv::Point(x, y), 2, fg_color, -1); | |
} else if(mask.at<uchar>(y, x) == cv::GC_BGD) { | |
cv::circle(scribbled_src, cv::Point(x, y), 2, bg_color, -1); | |
} else if(mask.at<uchar>(y, x) == cv::GC_PR_BGD) { | |
cv::Vec3b& pix = scribbled_src.at<cv::Vec3b>(y, x); | |
pix[0] = (uchar)(pix[0] * alpha + bg_color[0] * (1-alpha)); | |
pix[1] = (uchar)(pix[1] * alpha + bg_color[1] * (1-alpha)); | |
pix[2] = (uchar)(pix[2] * alpha + bg_color[2] * (1-alpha)); | |
} else if(mask.at<uchar>(y, x) == cv::GC_PR_FGD) { | |
cv::Vec3b& pix = scribbled_src.at<cv::Vec3b>(y, x); | |
pix[0] = (uchar)(pix[0] * alpha + fg_color[0] * (1-alpha)); | |
pix[1] = (uchar)(pix[1] * alpha + fg_color[1] * (1-alpha)); | |
pix[2] = (uchar)(pix[2] * alpha + fg_color[2] * (1-alpha)); | |
} | |
} | |
} | |
cv::imshow(name, scribbled_src); | |
cv::imshow(name + "_FG", getFG()); | |
} | |
void execute(){ | |
std::cout << "computing..."; | |
cv::grabCut(src, mask, cv::Rect(), bgd, fgd, 1, cv::GC_INIT_WITH_MASK); | |
std::cout << "end." << std::endl; | |
}; | |
cv::Mat getBinMask(){ | |
cv::Mat binmask(mask.size(), CV_8U); | |
binmask = mask & 1; | |
return binmask; | |
}; | |
cv::Mat getFG(){ | |
cv::Mat fg = cv::Mat::zeros(src.size(), src.type()); | |
src.copyTo(fg, getBinMask()); | |
return fg; | |
}; | |
template <class Func> | |
void mainLoop(Func& func){ | |
while(1){ | |
int key = cv::waitKey(1); | |
if(key == '\x1b') | |
break; | |
func(this, key); | |
show(); | |
} | |
}; | |
}; | |
int main(){ | |
const std::string input_filename("bird.bmp"); | |
cv::Mat input_image = cv::imread(input_filename); | |
InteractiveGrabcut igc(input_image); | |
igc.prepareWindow("bird"); | |
igc.mainLoop([](InteractiveGrabcut* self, int key)->void { | |
if(key == ' '){ | |
self->execute(); | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Consider making line 114:
void mainLoop(Func& func)
into:
void mainLoop(Func&& func)
or even:
void mainLoop(const Func& func)
else compiling with g++ gives the following as an error:
no known conversion for argument 1 from ‘main(int, char**)::<lambda(InteractiveGrabcut*, int)>’ to ‘main(int, char**)::<lambda(InteractiveGrabcut*, int)>&’
(refer to http://stackoverflow.com/a/8100310 for a similar problem)