def slid_clahe(img, limit=2, grid=(3, 3), iters=5): """repair using CLAHE algorithm (adaptive histogram equalization)""" img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) for i in range(iters): img = cv2.createCLAHE(clipLimit=limit, \ tileGridSize=grid).apply(img) debug.image(img).save("slid_clahe_@1") if limit != 0: kernel = np.ones((10, 10), np.uint8) img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) debug.image(img).save("slid_clahe_@2") return img
def pSLID(img, thresh=150): """find all lines using different settings""" print(utils.call("pSLID(img)")) segments = [] i = 0 for key, arr in enumerate(NC_SLID_CLAHE): tmp = slid_clahe(img, limit=arr[0], grid=arr[1], iters=arr[2]) __segments = list(slid_detector(slid_canny(tmp), thresh)) segments += __segments i += 1 print("FILTER: {} {} : {}".format(i, arr, len(__segments))) debug.image(slid_canny(tmp)).lines(__segments).save("pslid_F%d" % i) return segments
def llr_pad(four_points, img): print(utils.call("llr_pad(four_points)")) pco = pyclipper.PyclipperOffset() pco.AddPath(four_points, pyclipper.JT_MITER, pyclipper.ET_CLOSEDPOLYGON) padded = pco.Execute(60)[0] debug.image(img) \ .points(four_points, color=(0,0,255)) \ .points(padded, color=(0,255,0)) \ .lines([[four_points[0], four_points[1]], [four_points[1], four_points[2]], \ [four_points[2], four_points[3]], [four_points[3], four_points[0]]], \ color=(255,255,255)) \ .lines([[padded[0], padded[1]], [padded[1], padded[2]], \ [padded[2], padded[3]], [padded[3], padded[0]]], \ color=(255,255,255)) \ .save("llr_final_pad") return pco.Execute(60)[ 0] # 60,70/75 is best (with buffer/for debug purpose)
def LAPS(img, lines, size=10): print(utils.call("LAPS(img, lines)")) __points, points = laps_intersections(lines), [] debug.image(img).points(__points, size=3).save("laps_in_queue") for pt in __points: # pixels are in integers pt = list(map(int, pt)) # size of our analysis area lx1 = max(0, int(pt[0] - size - 1)) lx2 = max(0, int(pt[0] + size)) ly1 = max(0, int(pt[1] - size)) ly2 = max(0, int(pt[1] + size + 1)) # cropping for detector dimg = img[ly1:ly2, lx1:lx2] dimg_shape = np.shape(dimg) # not valid if dimg_shape[0] <= 0 or dimg_shape[1] <= 0: continue # use neural network re_laps = laps_detector(dimg) if not re_laps[0]: continue # add if okay if pt[0] < 0 or pt[1] < 0: continue points += [pt] points = laps_cluster(points) debug.image(img).points(points, size=5, \ color=debug.color()).save("laps_good_points") return points
def SLID(img, segments): # FIXME: zrobic 2 rodzaje haszowania (katy + pasy [blad - delta]) print(utils.call("SLID(img, segments)")) global all_points all_points = [] pregroup, group, hashmap, raw_lines = [[], []], {}, {}, [] __cache = {} def __dis(a, b): idx = hash("__dis" + str(a) + str(b)) if idx in __cache: return __cache[idx] __cache[idx] = np.linalg.norm(na(a) - na(b)) return __cache[idx] X = {} def __fi(x): if x not in X: X[x] = 0 if (X[x] == x or X[x] == 0): X[x] = x else: X[x] = __fi(X[x]) return X[x] def __un(a, b): ia, ib = __fi(a), __fi(b) X[ia] = ib group[ib] |= group[ia] #group[ia] = set() #group[ia] = set() # shortest path // height nln = lambda l1, x, dx: \ np.linalg.norm(np.cross(na(l1[1])-na(l1[0]), na(l1[0])-na( x)))/dx def __similar(l1, l2): da, db = __dis(l1[0], l1[1]), __dis(l2[0], l2[1]) # if da > db: l1, l2, da, db = l2, l1, db, da d1a, d2a = nln(l1, l2[0], da), nln(l1, l2[1], da) d1b, d2b = nln(l2, l1[0], db), nln(l2, l1[1], db) ds = 0.25 * (d1a + d1b + d2a + d2b) + 0.00001 #print(da, db, abs(da-db)) #print(int(da/ds), int(db/ds), "|", int(abs(da-db)), int(da+db), # int(da+db)/(int(abs(da-db))+0.00001)) alfa = 0.0625 * (da + db) #15 # FIXME: roznica??? #if d1 + d2 == 0: d1 += 0.00001 # [FIXME]: divide by 0 t1 = (da / ds > alfa and db / ds > alfa) if not t1: return False # [FIXME]: dist??? return True def __generate(a, b, n): points = [] t = 1 / n for i in range(n): x = a[0] + (b[0] - a[0]) * (i * t) y = a[1] + (b[1] - a[1]) * (i * t) points += [[int(x), int(y)]] return points def __analyze(group): global all_points points = [] for idx in group: points += __generate(*hashmap[idx], 10) _, radius = cv2.minEnclosingCircle(na(points)) w = radius * (math.pi / 2) vx, vy, cx, cy = cv2.fitLine(na(points), cv2.DIST_L2, 0, 0.01, 0.01) # debug.color() all_points += points return [[int(cx - vx * w), int(cy - vy * w)], [int(cx + vx * w), int(cy + vy * w)]] for l in segments: h = hash(str(l)) t1 = l[0][0] - l[1][0] t2 = l[0][1] - l[1][1] hashmap[h] = l group[h] = set([h]) X[h] = h if abs(t1) < abs(t2): pregroup[0].append(l) else: pregroup[1].append(l) debug.image(img.shape) \ .lines(pregroup[0], color=debug.color()) \ .lines(pregroup[1], color=debug.color()) \ .save("slid_pre_groups") for lines in pregroup: for i in range(len(lines)): l1 = lines[i] h1 = hash(str(l1)) #print(h1, __fi(h1)) if (X[h1] != h1): continue #if (__fi(h1) != h1): continue for j in range(i + 1, len(lines)): l2 = lines[j] h2 = hash(str(l2)) #if (__fi(h2) != h2): continue if (X[h2] != h2): continue #if (len(group[h2])==0): continue if not __similar(l1, l2): continue __un(h1, h2) # union & find # break # FIXME __d = debug.image(img.shape) for i in group: #if (__fi(i) != i): continue if (X[i] != i): continue #if len(group[i]) == 0: continue ls = [hashmap[h] for h in group[i]] __d.lines(ls, color=debug.color()) __d.save("slid_all_groups") for i in group: #if (__fi(i) != i): continue if (X[i] != i): continue #if len(group[i]) == 0: continue #if (__fi(i) != i): continue raw_lines += [__analyze(group[i])] debug.image(img.shape).lines(raw_lines).save("slid_final") debug.image(img.shape)\ .points(all_points, color=(0,255,0), size=2)\ .lines(raw_lines).save("slid_final2") return raw_lines
def LLR(img, points, lines): print(utils.call("LLR(img, points, lines)")) old = points # --- otoczka def __convex_approx(points, alfa=0.01): hull = scipy.spatial.ConvexHull(na(points)).vertices cnt = na([points[pt] for pt in hull]) approx = cv2.approxPolyDP(cnt,alfa*\ cv2.arcLength(cnt,True),True) return llr_normalize(itertools.chain(*approx)) # --- # --- geometria __cache = {} def __dis(a, b): idx = hash("__dis" + str(a) + str(b)) if idx in __cache: return __cache[idx] __cache[idx] = np.linalg.norm(na(a) - na(b)) return __cache[idx] nln = lambda l1, x, dx: \ np.linalg.norm(np.cross(na(l1[1])-na(l1[0]), na(l1[0])-na( x)))/dx # --- pregroup = [[], []] # podzial na 2 grupy (dla ramki) S = {} # ranking ramek // wraz z wynikiem points = llr_correctness(llr_normalize(points), img.shape) # popraw punkty # --- clustrowanie import sklearn.cluster __points = {} points = llr_polysort(points) __max, __points_max = 0, [] alfa = math.sqrt(cv2.contourArea(na(points)) / 49) X = sklearn.cluster.DBSCAN(eps=alfa * 4).fit(points) # **(1.3) for i in range(len(points)): __points[i] = [] for i in range(len(points)): if X.labels_[i] != -1: __points[X.labels_[i]] += [points[i]] for i in range(len(points)): if len(__points[i]) > __max: __max = len(__points[i]) __points_max = __points[i] if len(__points) > 0 and len(points) > 49 / 2: points = __points_max print(X.labels_) # --- # tworzymy zewnetrzny pierscien ring = __convex_approx(llr_polysort(points)) n = len(points) beta = n * (5 / 100) # beta=n*(100-(skutecznosc LAPS)) alfa = math.sqrt(cv2.contourArea(na(points)) / 49) # srednia otoczka siatki x = [p[0] for p in points] # szukamy punktu y = [p[1] for p in points] # centralnego skupiska centroid = (sum(x) / len(points), \ sum(y) / len(points)) print(alfa, beta, centroid) # C (x2, y2) d=(x_1−x_0)^2+(y_1−y_0)^2, t=d_t/d # B (x1, y1) (x_2,y_2)=(((1−t)x_0+tx_1),((1−t)y_0+ty_1)) # . t=(x_0-x_2)/(x_0-x_1) # . # A (x0, y0) def __v(l): y_0, x_0 = l[0][0], l[0][1] y_1, x_1 = l[1][0], l[1][1] x_2 = 0 t = (x_0 - x_2) / (x_0 - x_1 + 0.0001) a = [int((1 - t) * x_0 + t * x_1), int((1 - t) * y_0 + t * y_1)][::-1] x_2 = img.shape[0] t = (x_0 - x_2) / (x_0 - x_1 + 0.0001) b = [int((1 - t) * x_0 + t * x_1), int((1 - t) * y_0 + t * y_1)][::-1] poly1 = llr_polysort([[0, 0], [0, img.shape[0]], a, b]) s1 = llr_polyscore(na(poly1), points, centroid, beta=beta, alfa=alfa / 2) poly2 = llr_polysort([a, b, \ [img.shape[1],0], [img.shape[1],img.shape[0]]]) s2 = llr_polyscore(na(poly2), points, centroid, beta=beta, alfa=alfa / 2) return [a, b], s1, s2 def __h(l): x_0, y_0 = l[0][0], l[0][1] x_1, y_1 = l[1][0], l[1][1] x_2 = 0 t = (x_0 - x_2) / (x_0 - x_1 + 0.0001) a = [int((1 - t) * x_0 + t * x_1), int((1 - t) * y_0 + t * y_1)] x_2 = img.shape[1] t = (x_0 - x_2) / (x_0 - x_1 + 0.0001) b = [int((1 - t) * x_0 + t * x_1), int((1 - t) * y_0 + t * y_1)] poly1 = llr_polysort([[0, 0], [img.shape[1], 0], a, b]) s1 = llr_polyscore(na(poly1), points, centroid, beta=beta, alfa=alfa / 2) poly2 = llr_polysort([a, b, \ [0, img.shape[0]], [img.shape[1], img.shape[0]]]) s2 = llr_polyscore(na(poly2), points, centroid, beta=beta, alfa=alfa / 2) return [a, b], s1, s2 for l in lines: # bedziemy wszystkie przegladac for p in points: # odrzucamy linie ktore nie pasuja # (1) linia przechodzi blisko dobrego punktu t1 = nln(l, p, __dis(*l)) < alfa # (2) linia przechodzi przez srodek skupiska t2 = nln(l, centroid, __dis(*l)) > alfa * 2.5 # 3 # (3) linia nalezy do pierscienia # t3 = True if p in ring else False if t1 and t2: #if (t1 and t2) or (t1 and t3 and t2): # [1 and 2] or [1 and 3 and 2] tx, ty = l[0][0] - l[1][0], l[0][1] - l[1][1] if abs(tx) < abs(ty): ll, s1, s2 = __v(l) o = 0 else: ll, s1, s2 = __h(l) o = 1 if s1 == 0 and s2 == 0: continue pregroup[o] += [ll] pregroup[0] = llr_unique(pregroup[0]) pregroup[1] = llr_unique(pregroup[1]) debug.image(img) \ .lines(lines, color=(0,0,255)) \ .points(laps_intersections(lines), color=(255,0,0), size=2) \ .save("llr_debug_1") debug.image(img) \ .points(laps_intersections(lines), color=(0,0,255), size=2) \ .points(old, color=(0,255,0)) \ .save("llr_debug_2") debug.image(img) \ .lines(lines, color=(0,0,255)) \ .points(points, color=(0,0,255)) \ .points(ring, color=(0,255,0)) \ .points([centroid], color=(255,0,0)) \ .save("llr_debug") debug.image(img) \ .lines(pregroup[0], color=(0,0,255)) \ .lines(pregroup[1], color=(255,0,0)) \ .save("llr_pregroups") print("---------------------") for v in itertools.combinations(pregroup[0], 2): # poziome for h in itertools.combinations(pregroup[1], 2): # pionowe poly = laps_intersections([v[0], v[1], h[0], h[1]]) # przeciecia poly = llr_correctness(poly, img.shape) # w obrazku if len(poly) != 4: continue # jesl. nie ma poly = na(llr_polysort(llr_normalize(poly))) # sortuj if not cv2.isContourConvex(poly): continue # wypukly? S[-llr_polyscore(poly, points, centroid, \ beta=beta, alfa=alfa/2)] = poly # dodaj S = collections.OrderedDict(sorted(S.items())) # max K = next(iter(S)) print("key --", K) four_points = llr_normalize(S[K]) # score # XXX: pomijanie warst, lub ich wybor? (jesli mamy juz okay) # XXX: wycinanie pod sam koniec? (modul wylicznia ile warstw potrzebnych) print("POINTS:", len(points)) print("LINES:", len(lines)) debug.image(img).points(four_points).save("llr_four_points") debug.image(img) \ .points(points, color=(0,255,0)) \ .points(four_points, color=(0,0,255)) \ .points([centroid], color=(255,0,0)) \ .lines([[four_points[0], four_points[1]], [four_points[1], four_points[2]], \ [four_points[2], four_points[3]], [four_points[3], four_points[0]]], \ color=(255,255,255)) \ .save("llr_debug_3") return four_points