尝试用图像处理来实现UI设计稿的自动标注

来源:互联网 发布:知乎有mac版吗 编辑:程序博客网 时间:2024/06/06 05:30
这篇博客比较适合像我这样的图像处理小白,里面包含了遇到问题时的解决思路,和一些opencv函数用法。这仅仅是一次尝试,如果效果可以或许可以做成一个项目。

想法由来

假期实习的时候,做的是前端,遇到的最大的问题就是等UI设计师的设计稿,当设计稿中的内容比较多的时候,设计师基本会炸,因为这意味着要浪费大量的时间在标  注上面,所以就在想能不能解决这个问题。其实刚开始我一直以为做一个PS插件就能搞定,是我想太简单了,因为不同设计师在设计的时候,他们的操作习惯是不一样的,还有就是在合并图层后一些内容元素的信息是会丢失的,这大概是我至今还没看到PS的标注插件的原因吧。一张设计稿需要标注的内容无非就是长,宽,边距和颜色,或许可以尝试一下用图像处理的方式来解决该问题。

效果图

思路

首先来看一张设计稿




通过观察不难发现,不管是按钮,文字还是图标我们都可以用矩来进行描述,而矩对应的长宽属性正好是我们需要的,具体怎么理解看下图:

所以可以明确现在我们需要做一下几件事:
  1. 提取矩形轮廓
  2. 提取轮廓颜色

提取矩形轮廓

很幸运,opencv已经给我们提供了相关的方法来提取轮廓和求凸包最小环绕矩形,这两个方法分别是findContoursboundingRect,先来看一段代码:

void todo(){       Mat src;  //图源       Mat img;  //处理图       Mat dst;  //输出图       src=imread("");       img.create(src.rows,src.cols,src.depth());       dst=src;       cvtColor(src, img, CV_BGR2GRAY);       threshold(img, img, 0, 255, CV_THRESH_OTSU);//findContours需要输入二值图形       vector<vector<Point>> contours;       vector<Vec4i> hierarchy;       findContours(img,contours,hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_NONE);//获取轮廓       CvScalar color = CV_RGB(255,0,0);       for(vector<Point> contour:contours){              Rect rect=boundingRect(contour);  //求凸包              DrawMark(dst,src,rect,color,0,contour);//绘画标记       }       imshow("",dst);       src.release();       img.release();       dst.release();       cvWaitKey (0);}

效果图


观察图案,存在问题 1.图标未识别 2.文字细节太多

问题分析和解决方法

图标未识别
造成该问题的原因是阈值函数threshold函数二值化图片后造成的,先来看一下二值化后的图片:



很明显图标已经丢失,原因是我们用的二值化方法CV_THRESH_OTSU(大津法)造成的,该方法可以全局自适应阈值,滤掉了和背景色接近的图标。当然也可以用其他方法手动设置阈值,但是这样太麻烦,这就意味着这将是一个用户参数,这必然增加用户的学习成本。所以现在需要采取其他方法来对findContours的输入图像进行二值化。

文字细节太多
消除噪点:我们并不关心过小的细节,只需要能突出整体,突出重点就对了,专业术语也就是消除噪点,消除噪点的方式很多比如滤波,腐蚀膨胀等,但是根据场景我们这里要用形态学中的腐蚀膨胀操作,好处是它可以分割出独立图像元素,连接图中相邻元素,而且还可以输出二值图像,这样基本能解决上面的问题。现在我们将threshold操作改为腐蚀膨胀操作:
      int erosion_type;      int erosion_elem=0;      int erosion_size=7;    if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }    else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }    else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }    Mat element = getStructuringElement( erosion_type,                                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),                                       Point( erosion_size, erosion_size ) );      morphologyEx(img, img, MORPH_GRADIENT, element);      //高亮处理      for( size_t i = 0; i < img.rows; i++)        {     uchar* data = img.ptr<uchar>(i);     for(size_t j = 0; j < img.cols*img.channels(); j++)     {  if(data[j]>10)    data[j]=255;else            data[j]=0;    }        }        //腐蚀还原      erode( img, img, element );
这里我们用高级形态学方法morphologyEx,该方法能图像进行开,闭和梯度等操作,在这里我们选择MORPH_GRADIENT进行梯度操作,而形态学梯度正好就是突出外围-轮廓,这和我们的目标是提取轮廓不谋而合。这里需要注意的是element是我们的核,那么参数erosion_size就是图像向里收缩和向外膨胀的距离,该参数取决于设计稿的大小和设计稿中最小元素的大小,腐蚀膨胀具体内容可参考《数字图像处理》一书,需要注意的是我们的腐蚀膨胀是针对的高亮区域,所以我们有必要对梯度操作后的图像进行高亮处理,梯度操作后我们得到的轮廓实际上是膨胀的轮廓,比实际轮廓要大,所以我们还需要进行腐蚀操作还原到正常大小。来看看每一步操作后的图像:

                                                                    梯度操作

                                                                   高亮操作

                                                                 还原操作

                                                                  效果图
来看看更复杂一些的设计稿标注:

  


边距提取(待解决)
颜色提取(待解决)
阅读全文
0 0