Ejemplo n.º 1
0
def cluster_by_rho(theta_groups):
    result_group = []  # 合并后的分组线
    rho_differ = 7
    for gp in theta_groups:
        # 按 rho 的大小排序的 line 列表
        rho_lines = sorted([li for li in gp], key=lambda li: li.rho)
        rho_ls = [li.rho for li in rho_lines]
        rho_diff = np.diff(rho_ls)  # calculate diff in theta_ls which have been sorted
        rho_diff_idx = np.where(rho_diff > rho_differ)[0] + 1  # slice by std value
        rho_diff_idx = np.append(rho_diff_idx, [len(rho_lines)])  # line_ls 长度作为最后一个
        rho_groups = []  # 按 rho 分组
        gp_rho_ls = []
        for i, idx in enumerate(rho_diff_idx):  # 邻近的diff theta 分组
            if i == 0:
                rho_groups.append(rho_lines[0: idx])
                gp_rho_ls.append(rho_ls[0: idx])
            else:
                rho_groups.append(rho_lines[rho_diff_idx[i - 1]:idx])
                gp_rho_ls.append(rho_ls[rho_diff_idx[i - 1]:idx])
        # 在分组内(rho 和 theta 都接近的情况下)
        new_lines = []
        for lis in rho_groups:
            if len(lis) > 1:  # 合并在同一直线上的直线段
                pts = []
                for li in lis:
                    pts.extend(li.getLinePts(includeEndPt=True))
                new_li = GLine().fit(pts)
                calculate_theta_rho(new_li)
                new_lines.append(new_li)
            elif len(lis) == 1:
                new_lines.append(lis[0])
        result_group.append(new_lines)
    return result_group
Ejemplo n.º 2
0
def lineDetect(img, mode=0, threshold=-1, minLineLength=0, maxLineGap=0):
    img = cv2.cvtColor(img, code=cv2.COLOR_BGR2GRAY) if img.ndim == 3 else img
    lines = []
    if mode == 0:  # 霍夫直线检测
        # 参数 rho:累加器距离分辨率,  theta:累加器角度分辨率   threshold:投票阈值,  minLineLength:直线的最小长度  maxLineGap:直线合并最大断开距离
        datas = cv2.HoughLinesP(img, rho=1, theta=np.pi / 360., threshold=int(threshold), minLineLength=minLineLength,
                                maxLineGap=maxLineGap)
        if datas is None:
            return lines
        for d in datas.reshape(-1, 4):
            line = GLine().initXY(*d)
            if line.getLen() <= 0: continue
            lines.append(line)
    elif mode == 1:  # 直线检测器检测
        # 直线检测器检测 cv2.createLineSegmentDetector
        # 参数1 refine(LSD_REFINE_STD,): 调优策略, cv2.LSD_REFINE_NONE:无调优策略, cv2.LSD_REFINE_STD:标准调优策略,将弧分解成多个小线段, cv2.LSD_REFINE_ADV:使用NFA指标评价检测直线,调整参数近一步调优检测直线
        # 参数2 scale(0.8): 缩放图像比例   参数3 sigma_scale(0.6): 高斯模糊核sigma=sigma_scale/scale   参数4 quant(2.0):梯度量化误差
        # 参数5 ang_th(22.5):直线段角度容差  参数6 log_eps(0): NFA检测阈值  参数7 density_th(0.7):直线段密度阈值   参数8 n_bins(1024):梯度归一化数量
        lsd = cv2.createLineSegmentDetector(cv2.LSD_REFINE_STD)
        datas, width, prec, nfa = lsd.detect(img)
        if datas is None and width is None and prec is None and nfa is None: print("检测失败,未能检测到直线");return lines
        datas = datas.reshape(-1, 4)
        width = width.reshape(-1).tolist()
        prec = prec.reshape(-1).tolist()
        for i in range(len(datas)):
            line = GLine().initXY(*datas[i])
            if line.getLen() <= 0: continue
            line.width, line.prec = width[i], prec[i]
            lines.append(line)
    else:
        pass
    return lines
Ejemplo n.º 3
0
    def fuse(baseline, line):
        tlen = baseline.getLen() + line.getLen()
        lineTh = max(tlen * maxRatio, minDis)  # 直线间隔阈值
        segTh = tlen * segRatio  # 线段间隔阈值

        pts = [line.pt1, line.pt2]
        lineDis = [baseline.distance(p, mode=0) for p in pts]  # 直线距离取最大
        segDis = [baseline.distance(p, mode=1) for p in pts]  # 线段距离取最小

        # 直线距离超过阈值, 或者断开距离超过阈值, 不能融合
        if max(lineDis) > lineTh or min(segDis) > segTh: return False
        pt1, pt2, dis = getMaxLinesLen([baseline, line])
        if abs(dis - baseline.getLen()) < 0.01: return True

        pts = baseline.getLinePts(True)
        pts.extend(line.getLinePts(True))

        resline = GLine().fit(pts)
        pt1 = resline.getVertPt(pt1)
        pt2 = resline.getVertPt(pt2)
        baseline.initPts(pt1, pt2)
        return True
Ejemplo n.º 4
0
    def isParallel(self, line, PDDR=0.05, overlapRatio=0.3, lineMindis=-1, lineMaxdis=-1):
        # 考虑因素,直线距离, 重合率, 线段长度差异, 平行距离差异

        longLine, shortLine = (self, line) if self.getLen() > line.getLen() else (line, self)
        llen, slen = longLine.getLen(), shortLine.getLen()
        if float(slen) / llen < overlapRatio: return False

        pts = [shortLine.pt1, shortLine.pt2]
        lineDis = [longLine.distance(p, mode=0) for p in pts]  # 直线距离
        lineDif = lineDis[0] + lineDis[1] if longLine.isCross(shortLine) else abs(lineDis[0] - lineDis[1])

        # 线是否平行
        if PDDR < 1 and lineDif > slen * PDDR: return False
        if PDDR > 1 and lineDif > PDDR: return False

        if overlapRatio <= 0: return True

        # 平行线的距离大于两线距离, 为干扰线
        if sum(lineDis) / 2 > slen + llen: return False
        if lineMindis > 0 and lineDis < lineMindis: return False
        if lineMaxdis > 0 and lineDis > lineMaxdis: return False

        # 计算重合率
        pt1 = longLine.getVertPt(shortLine.pt1)
        pt2 = longLine.getVertPt(shortLine.pt2)
        pt1.flag = longLine.isPtAtLineSeg(pt1)
        pt2.flag = longLine.isPtAtLineSeg(pt2)
        if pt1.flag and pt2.flag: return True  # 完全重合的情况
        if not pt1.flag and not pt2.flag: return False  # 完全不重合的请教

        # 计算重合率
        tmpLine = GLine(pt1, pt2)
        pt3 = longLine.pt1 if tmpLine.isPtAtLineSeg(longLine.pt1) else longLine.pt2
        dis1 = pt3.distance(pt1) if pt1.flag else pt3.distance(pt2)
        dis2 = pt1.distance(pt2)
        return dis1 / dis2 > overlapRatio
Ejemplo n.º 5
0
 def disLine0(a, b):
     if (a == b).all(): return 0
     linea = GLine().initXY(a[0], a[1], a[2], a[3])
     lineb = GLine().initXY(b[0], b[1], b[2], b[3])
     longline, shortline = (linea, lineb) if linea.getLen() > lineb.getLen() else (lineb, linea)
     pts = [shortline.pt1, shortline.pt2]
     dis = min([longline.distance(pt, mode=1) for pt in pts])
     angle = longline.angle(shortline)
     if angle > minAngle and dis < minDis: dis = minDis  # 当超过角度, 距离至少位mindis(使其不符号条件)
     return dis * (math.sin(math.radians(angle)) + 1)
Ejemplo n.º 6
0
 def getExtendLine(self, ratio=1.5):
     midPt = self.midPoint()
     x1, y1 = self.pt1.x + (self.pt1.x - midPt.x) * ratio, self.pt1.y + (self.pt1.y - midPt.y) * ratio
     x2, y2 = self.pt2.x + (self.pt2.x - midPt.x) * ratio, self.pt2.y + (self.pt2.y - midPt.y) * ratio
     return GLine().initXY(x1, y1, x2, y2)
Ejemplo n.º 7
0
 def getParaLine(self, pt):
     line = GLine()
     line.a, line.b, line.c = self.a, self.b, -self.a * pt.fx - self.b * pt.fy
     line.d = math.sqrt(line.a ** 2 + line.b ** 2)
     return line
Ejemplo n.º 8
0
 def getYAngle(self):
     line = GLine()
     line.a, line.b, line.c = 1, 0, 0
     return self.angle(line)
Ejemplo n.º 9
0
 def getXAngle(self):
     line = GLine()
     line.a, line.b, line.c = 0, 1, 0
     return self.angle(line)
Ejemplo n.º 10
0
 def midLine(self, line):
     if checkAnyNone(self.pt1, self.pt2, line.pt1, line.pt2): return None
     if self.pt1.distance(line.pt1) > self.pt1.distance(line.pt2):
         return GLine(self.pt1.midpoint(line.pt2), self.pt2.midpoint(line.pt1))
     else:
         return GLine(self.pt1.midpoint(line.pt1), self.pt2.midpoint(line.pt2))