工作中遇到了一个问题,好不容易解决了,写个博客了记录一下。
项目需要识别出汽车车前窗部分,通过ROI选取出来,再进行下一步的处理。我利用一些办法得到了如图1所示的轮廓,但是效果很不好。图中可见车窗四个边只有左侧、右侧和下侧轮廓,各个轮廓很不连续,断线问题很严重,并且这张图片已经是数据集里效果比较好的,还有更多的图片轮廓断线更为严重,直接提取ROI非常困难。
图1. 原始车窗识别效果
因为实验室光线的问题,轮廓的断线基本无法避免,利用传统CV算法补全很麻烦,而且不一定能适应所有的情况,我准备先用传统算法实现,然后下一步再利用深度学习的方法找出来车窗。想要真的适应更多的情况确实还是得用深度学习,后续我再写一篇分享一下,目前先分享我的传统CV解决方案。
我的思路是先把所有的点按边分类,分类完成后在对这些点进行拟合,然后对拟合的曲线进行修补和裁剪,防止轮廓出现凹陷的地方,最后再画一下轮廓就完成了。先把所有用到的包加载一下,sklearn用来拟合和分类,numba用来快速找两个多维数组的差异,其他的就是很常规的包。
import cv2
import numpy as np
import numba as nb
import copy as cp
from sklearn import linear_model
from sklearn.cluster import KMeans
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error as MSE
单独写出来的函数如下所示,
MSE_Singel
用来计算MSE,用于进一步分类所有的点。
setdiff2d_nb
这个函数用来寻找两个二维数组中的差异元素,运算速度非常快。
def MSE_Singel(y_pred, y):
return (y_pred-y)**2
def temp_imshow(size, idx):
class_left = np.full(size, 255)
class_left[list(idx[0]), list(idx[1])] = 0
class_left = class_left.astype(np.uint8)
cv2.namedWindow('left', 0)
cv2.imshow('left', class_left)
cv2.waitKey(0)
@nb.njit
def mul_xor_hash(arr, init=65537, k=37):
result = init
for x in arr.view(np.uint64):
result = (result * k) ^ x
return result
@nb.njit
def setdiff2d_nb(arr1, arr2):
# : build `delta` set using hashes
delta = {mul_xor_hash(arr2[0])}
for i in range(1, arr2.shape[0]):
delta.add(mul_xor_hash(arr2[i]))
# : compute the size of the result
n = 0
for i in range(arr1.shape[0]):
if mul_xor_hash(arr1[i]) not in delta:
n += 1
# : build the result
result = np.empty((n, arr1.shape[-1]), dtype=arr1.dtype)
j = 0
for i in range(arr1.shape[0]):
if mul_xor_hash(arr1[i]) not in delta:
result[j] = arr1[i]
j += 1
return result
首先需要导入图片,二值化处理一下。需要补全的四个边最好处理的就是左右两个,因为基本就是直线。我用了K-means来聚类,为了剔除上下两边的影响,先把图片切成了cut_top,cut_middle,cut_bottom三块,中间块就只有左右两条边,因此用中间块来聚类。
image = cv2.imread('base_pic1.jpg')
image_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
retVal, image_thresh = cv2.threshold(image_gray, 150, 255, cv2.THRESH_BINARY)
cv2.namedWindow('1', 0)
cv2.imshow('1', image_thresh)
cv2.waitKey(0)
#聚类
#1.照片三分类或者二分类,上半张图聚两类
image_cut = cp.copy(image_thresh)
H,