当前位置: 首页 > 科技观察

从具有特定规则的图片中提取轮廓

时间:2023-03-15 15:03:48 科技观察

背景目前,用户在线查看和选择汽车的方式相同。为了给用户提供更好的看车体验,足不出户就需要掌握360°车源详情。商家需收藏外观车源360°。在开发车智影+App外观采集和拍摄组件的过程中,发现如果仅通过示例图片引导商家在360°完成车源外观采集,效果很难达到由于拍摄距离和拍摄角度等问题的保证。实现思路首先将样本图像转化为Bitmap点,按照图像已知的特定规则从上、下、左、右四个方向扫描,扫描出四个边的点阵,合并点阵四个边,最后生成一个完整有序的点数组,然后将生成的点数组的每个点连接起来,生成一个闭合图的BezierPath。将遇到的“坑”四边的点数组直接合并,然后将每个点连接起来,生成一个闭合图的BezierPath。其实这个想法是有问题的。四边的点阵中有重复的点,将直接相邻的点连接起来,得到的图形就会如上图所示。如果只是简单的一行,就会遇到数组不连续点等问题。所以这里我们重新调整了实现思路,先对水平方向左右两侧的点数组进行加权,然后对垂直方向上下两侧的点数组进行加权。然后用垂直方向上下两边的点阵对左右两边的点阵进行补偿,最后将水平方向补偿后的左右两边的点阵进行合并。最终的实现思路和核心代码首先将图片转化为Bitmap点,按照特定规则从上下左右四个方向扫描(非透明像素点),扫描出NSMutableArray*arrLeft=[NSMutableArrayarray];NSMutableArray*arrBottom=[NSMutableArrayarray];NSMutableArray*arrRight=[NSMutableArrayarray];NSMutableArray*arrTop=[NSMutableArrayarray];for(NSIntegerrow=0;row=0;col--){constuint8_t*pixel=&rgba[row*bytesPerRow+col*bytesPerPixel];if(pixel[3]!=0x00){[arrRightinsertObject:[NSValuevalueWithCGPoint:CGPointMake(col,row)]atIndex:0];休息;}}}for(NSIntegercol=0;col=0;row--){constuint8_t*pixel=&rgba[row*bytesPerRow+col*bytesPerPixel];if(pixel[3]!=0x00){[arrBottomaddObject:[NSValuevalueWithCGPoint:CGPointMake(col,row)]];休息;}}//获取上面的点数组for(NSIntegerrow=0;row=0;i--){@autoreleasepool{NSValue*value=arrRight[i];if([arrLeftSetcontainsObject:value])[arrRightremoveObject:value];}}//移除顶部权重[arrBottomSetintersectSet:arrTopSet];对于(inti=(int)(arrTop.count-1);i>=0;i--){@autoreleasepool{NSValue*value=arrTop[i];if([arrBottomSetcontainsObject:value])[arrTopremoveObject:value];}}用上下边的点数组分别补偿左右边的点数组(这里的主要思路是找到重合点,然后补偿上下边重合点之间的点)lowersidestothepointarraysoftheleftandrightsides.补偿后的效果图如下)//arrFixPoints实际上是上或下点数组NSMutableSet*arrCoincidentPointsSet=[NSMutableSetsetWithArray:arrFixPoints];//arrOriginalPoints其实就是左点或者右点数组[arrCoincidentPointsSetintersectSet:[NSSetsetWithArray:arrOriginalPoints]];取出左右边点数组的头节点和尾节点元素,用上下边的点数组重新补偿,合并左右边的点数组,连接生成的每个点点数组,并生成一个闭合图的BezierPath//考虑特殊情况:如果示例图是矩形,之前的补偿方案就会有问题,所以取出左右底点,使用点数组下面再次补偿NSMutableArray*arrBottomOriginalPoints=[NSMutableArrayarray];NSValue*valueLB=arrLeftPoints.lastObject;NSValue*valueRB=arrRightPoints.firstObject;if(valueLB&&valueRB){[arrBottomOriginalPointsaddObject:valueLB];[arrBottomOriginalPointsaddObject:valueRB];arrBottomOriginalPoints=[selfhandleOriginalPoints:arrBottomOriginalPointsfixPoints:arrBottomPointsisDirectionRTL:YES];如果([arrBottomOriginalPoints.firstObjectisEqualToValue:valueLB]&&[arrBottomOriginalPoints.lastObjectisEqualToValue:valueRB]&&arrBottomOriginalPoints.count>2){for(inti=1;i<(arrBottomOriginalPoints.count-2);i++){@autoreleasepool{[arrLeftPointsaddObject:arrBottomOriginalPoints[i]];}}}}//取出左右顶部的点,用上面的点数组再次补偿NSMutableArray*arrTopOriginalPoints=[NSMutableArrayarray];NSValue*valueLT=arrLeftPoints.firstObject;NSValue*valueRT=arrRightPoints.lastObject;if(valueLT&&valueRT){[arrTopOriginalPointsaddObject:valueRT];[arrTopOriginalPointsaddObject:valueLT];arrTopOriginalPoints=[selfhandleOriginalPoints:arrTopOriginalPointsfixPoints:arrTopPointsisDirectionRTL]([arrTopOriginalPoints.firstObjectisEqualToValue:valueRT]&&[arrTopOriginalPoints.lastObjectisEqualToValue:valueLT]&&arrTopOriginalPoints.count>2){for(inti=1ropTop;i<(inarrTop。计数-2);i++){@autoreleasepool{[arrRightPointsaddObject:arrTopOriginalPoints[i]];}}}}NSMutableArray*arrPoints=[NSMutableArrayarray];if(arrLeftPoints.count)[arrPointsaddObjectsFromArray:arrLeftPoints];if(arrRightPoints.count)[arrPointsaddObjectsFromArray:arrRightPoints];效果展示结语图片获取轮廓的方案有很多,例如:OpenCV、Visionframework、DeepLab等,我们这次的需求中,示例图有特定的规则,所以获取轮廓并不是特别复杂。可以按照预期的思路一步步实现,所以最后我们没有引入额外的框架来实现。当然,上述获取大纲的思路不一定是最优解,未来还需要我们继续思考和优化。