因为教授让我去公司做演示,需要demo,暑假弄的小框架就派上了用场,现在需要在原来的基础上进一步完善
1.原来的主页面简化,主要目的是展示新的方法,旧方法太耗时,不适合现场演示,所以去掉旧方法部分,将新方法的qgraphicsview拉大
2.重复按打开文件时及时清理各显示块内容,qlabel对应clear(), qgraphicsscene对应clear之后,qgraphicsview要调用update才能清除内容
3.处理过程中的每一步都用mat数组记录下来,按detail按钮时一个个顺序显示,增加reset按钮便于从头开始播放
3.同时按教授要求需要提供用户自定义mask的功能,所以新添form类,在form.ui内只有两个大显示块,一个为原图,一个为选处理区域及展示处理后结果的区域
form的调用在之前有提到过
在qgraphicsview内检测鼠标动向的操作,可参考视频http://www.youtube.com/watch?v=d0CDMtfefB4
建立鼠标监视区域对象的类,将对象promote到新建类,在新建类内定义鼠标各类event及相关处理函数,代码就不在这里复述了
这里出现的问题是qgraphicsview新建的类在运行时出现错误,说什么convert qobject to qwidget的问题,其实是默认新建的类的构造函数为
explicit mouse(QObject *parent = 0);
将其中的qobject改为qwideget就可以了
4. 鼠标动作
Mouse events occur when a mouse button is pressed or released inside a widget, or when the mouse cursor is moved. Mouse move events will occur only when a mouse button is pressed down, unless mouse tracking has been enabled with QWidget::setMouseTracking().
建立mousePressEvent(QMouseEvent* ev)函数和mouseReleaseEvent()函数,鼠标在3中定义的监视区域qgraphicsview内按下和释放时产生QMouseEvent,进而调用这两个函数,并释放可传递到主页面的signal
获取鼠标位置时ev.x(),ev.y(),ev.pos()均为函数,注意前两个不要忘记加括号,第三个的返回值为QPointF类型
前面提到的位置是绝对位置,如果想要根据这些位置在鼠标区标示出来,则需要调用mapToScene(ev.pos())函数,这样返回的位置是相对于qgraphicsview内scene的位置。
void mouse::mousePressEvent(QMouseEvent* ev){
QPointF start_point= mapToScene(ev->pos());
this->x=start_point.x();
this->y=start_point.y();
emit Mouse_Pressed();
}
5.鼠标信号传递到主页面
在主页面类里创建鼠标按下时,主页面要产生的动作
private slots:
void Mouse_Pressed();
void Mouse_Released();
在主页面的构造函数内将监视区域产生的signal与主页面的动作相连。
connect(ui->resultView_proposed_user,SIGNAL(Mouse_Pressed()),this,SLOT(Mouse_Pressed()));
connect(ui->resultView_proposed_user,SIGNAL(Mouse_Released()),this,SLOT(Mouse_Released()));
6.根据鼠标运动,选择以显示的图像的一部分,并表示出来。
在qgraphicsscene内添加item,并在qgraphicsview里显示新的scene
setBrush(QBrush(Qt::blue)), 可设置填充颜色
a)b)的情况一次鼠标按下和释放定义的区域如果不满意,再次选择时需要及时清除上次的选择记录。不确定是不是有办法只去除scene中的一个item而不影响原图像,我采用的比较单纯的方法,在按下鼠标时清除全部scene,然后只显示原图像
resultScene_proposed_user->clear();
resultScene_proposed_user->addPixmap(*pix_user);
ui->resultView_proposed_user->show();
a)以鼠标按下点和释放点为界,选择方形区域。
QGraphicsRectItem* item_rect=new QGraphicsRectItem(ui->resultView_proposed_user->x,ui->resultView_proposed_user->y,ui->resultView_proposed_user->width,ui->resultView_proposed_user->height);
item_rect->setBrush(QBrush(Qt::blue));
resultScene_proposed_user->addItem(item_rect);
ui->resultView_proposed_user->show();
b)以鼠标按下点和释放点为界,选择椭圆形区域。
QGraphicsEllipseItem* item_elli=new QGraphicsEllipseItem(ui->resultView_proposed_user->x,ui->resultView_proposed_user->y,ui->resultView_proposed_user->width,ui->resultView_proposed_user->height);
item_elli->setBrush(QBrush(Qt::red));
resultScene_proposed_user->addItem(item_elli);
ui->resultView_proposed_user->show();椭圆形item的创建方法中,参数可以设定为方形区域
Constructs a QGraphicsEllipseItem using rect as the default rectangle. parent is passed to QAbstractGraphicsShapeItem's constructor.
c)选择所以鼠标经过的区域。
待续!
7.因为6中提到了三种不同形状的选择方式,所以在主页面中添加checkbox,允许用户选择相应的选择形状。
事先选择将一个checkbox选成checked,所有checkbox都选为autoExclusive,可以保证有初始值,且不会存在同时选了两个形状的情况
8. 根据鼠标选择的部位建立新的mask文件,用于Inpainting.
建立文件之前先判断选择区域是否合法,有没有超出原图像的范围;文件建立之后判断是否创建成功
a)方形区域
Rect roi(ui->resultView_proposed_user->x,ui->resultView_proposed_user->y,ui->resultView_proposed_user->width,ui->resultView_proposed_user->height);
Mat pixel_roi=image(roi);
pixel_roi=Scalar(255,255,255);b)椭圆形区域
cv::RotatedRect roi=cv::RotatedRect(Point2f(ui->resultView_proposed_user->x+ui->resultView_proposed_user->width/2,ui->resultView_proposed_user->y+ui->resultView_proposed_user->height/2),Size2f(ui->resultView_proposed_user->width,ui->resultView_proposed_user->height),0);
cv::ellipse(image,roi,Scalar(255,255,255),CV_FILLED,8);cv::ellipse要求的roi为rotatedrect类型,rotatedrect构造函数第一个参量为Point2f类型,定义中心点;第二个参量为size2f,定义长短轴;第三个参量为选择角度
cv::ellipse函数第四个参量cv_filled表示颜色填充到椭圆内部,否则定义的颜色只针对椭圆边缘线
c)任意形状区域
待续!
9. 新增的自定义主页面需要调用起始主页面中定义的全局变量和函数,如canny edge detector等,如果不在自定义主页面重新定义,则调用无效;如果跟起始页面一样定义,则提示重复定义错误。
解决方法是在新增页面里将起始主页面以定义,并被新增页面需要的参量定义为extern 类型,即
extern std::string mask_name;
extern double f;
extern void CannyThreshold(int, void*);
extern可以置于变量或函数前,以在别的文件中标识变量或函数的定义,并提示编译器遇到此变量或函数时在其他模块中寻找其定义。extern是C、C++语言中表明函数和全局变量作用范围(可见性)的关键字。对于extern变量来说,仅仅是一个变量的声明,其并不是定义,不会分配内存空间。
关于extern和static区别可参见http://blog.youkuaiyun.com/zhangzheng0413/article/details/7569226
10.目前结果
起始页面:
新增页面:
11. 下一步,完成选择随意区域,美化界面