def get_contour(self, rescaled_image): """ Returns a numpy array of shape (4, 2) containing the vertices of the four corners of the document in the image. It considers the corners returned from get_corners() and uses heuristics to choose the four corners that most likely represent the corners of the document. If no corners were found, or the four corners represent a quadrilateral that is too small or convex, it returns the original four corners. """ # these constants are carefully chosen MORPH = 9 CANNY = 84 HOUGH = 25 IM_HEIGHT, IM_WIDTH, _ = rescaled_image.shape # convert the image to grayscale and blur it slightly gray = cv2.cvtColor(rescaled_image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7, 7), 0) # dilate helps to remove potential holes between edge segments kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (MORPH, MORPH)) dilated = cv2.dilate(gray, kernel) # find edges and mark them in the output map using the Canny algorithm edged = cv2.Canny(dilated, 0, CANNY) test_corners = self.get_corners(edged) approx_contours = [] if len(test_corners) >= 4: quads = [] for quad in itertools.combinations(test_corners, 4): points = np.array(quad) points = transform.order_points(points) points = np.array([[p] for p in points], dtype="int32") quads.append(points) # get top five quadrilaterals by area quads = sorted(quads, key=cv2.contourArea, reverse=True)[:5] # sort candidate quadrilaterals by their angle range, which helps remove outliers quads = sorted(quads, key=self.angle_range) approx = quads[0] if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) # for debugging: uncomment the code below to draw the corners and countour found # by get_corners() and overlay it on the image # cv2.drawContours(rescaled_image, [approx], -1, (20, 20, 255), 2) # plt.scatter(*zip(*test_corners)) # plt.imshow(rescaled_image) # plt.show() # also attempt to find contours directly from the edged image, which occasionally # produces better results (_, cnts, hierarchy) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5] # loop over the contours for c in cnts: # approximate the contour approx = cv2.approxPolyDP(c, 80, True) if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) break # If we did not find any valid contours, just use the whole image if not approx_contours: TOP_RIGHT = (IM_WIDTH, 0) BOTTOM_RIGHT = (IM_WIDTH, IM_HEIGHT) BOTTOM_LEFT = (0, IM_HEIGHT) TOP_LEFT = (0, 0) screenCnt = np.array([[TOP_RIGHT], [BOTTOM_RIGHT], [BOTTOM_LEFT], [TOP_LEFT]]) else: screenCnt = max(approx_contours, key=cv2.contourArea) return screenCnt.reshape(4, 2)
def get_contour(self, image): """ Returns a numpy array of shape (4, 2) containing the vertices of the four corners of the document in the image. It considers the corners returned from get_corners() and uses heuristics to choose the four corners that most likely represent the corners of the document. If no corners were found, or the four corners represent a quadrilateral that is too small or convex, it returns the original four corners. """ # these constants are carefully chosen MORPH = 9 CANNY = 84 HOUGH = 25 IM_HEIGHT, IM_WIDTH, _ = image.shape # convert the image to grayscale and blur it slightly gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7,7), 0) # dilate helps to remove potential holes between edge segments kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH)) dilated = cv2.dilate(gray, kernel) # find edges and mark them in the output map using the Canny algorithm edged = cv2.Canny(dilated, 0, CANNY) test_corners = self.get_corners(edged) approx_contours = [] if len(test_corners) >= 4: quads = [] for quad in itertools.combinations(test_corners, 4): points = np.array(quad) points = transform.order_points(points) points = np.array([[p] for p in points], dtype = "int32") quads.append(points) # get top five quadrilaterals by area quads = sorted(quads, key=cv2.contourArea, reverse=True)[:5] # sort candidate quadrilaterals by their angle range, which helps remove outliers quads = sorted(quads, key=self.angle_range) approx = quads[0] if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) # for debugging: uncomment the code below to draw the corners and countour found # by get_corners() and overlay it on the image # cv2.drawContours(rescaled_image, [approx], -1, (20, 20, 255), 2) # plt.scatter(*zip(*test_corners)) # plt.imshow(rescaled_image) # plt.show() # also attempt to find contours directly from the edged image, which occasionally # produces better results (_, cnts, hierarchy) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5] # loop over the contours for c in cnts: # approximate the contour approx = cv2.approxPolyDP(c, 80, True) if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) break # If we did not find any valid contours, just use the whole image if not approx_contours: # TOP_RIGHT = (IM_WIDTH, 0) # BOTTOM_RIGHT = (IM_WIDTH, IM_HEIGHT) # BOTTOM_LEFT = (0, IM_HEIGHT) # TOP_LEFT = (0, 0) # screenCnt = np.array([[TOP_RIGHT], [BOTTOM_RIGHT], [BOTTOM_LEFT], [TOP_LEFT]]) # image = cv2.imread("79.png") # print(type(image)) # orig=input() # orig = image.copy() (H, W) = image.shape[:2] print(image.shape[:2]) height = image.shape[0] width = image.shape[1] # set the new width and height and then determine the ratio in change # for both the width and height (newW, newH) = (3008,4032) rW = W / float(newW) rH = H / float(newH) # resize the image and grab the new image dimensions image = cv2.resize(image, (newW, newH)) (H, W) = image.shape[:2] print(image.shape[:2]) # define the two output layer names for the EAST detector model that # we are interested -- the first is the output probabilities and the # second can be used to derive the bounding box coordinates of text layerNames = [ "feature_fusion/Conv_7/Sigmoid", "feature_fusion/concat_3"] # load the pre-trained EAST text detector print("[INFO] loading EAST text detector...") net = cv2.dnn.readNet("E:/Users/NM/envs/cv/aidl/opencv-text-detection/opencv-text-detection/frozen_east_text_detection.pb") # construct a blob from the image and then perform a forward pass of # the model to obtain the two output layer sets blob = cv2.dnn.blobFromImage(image, 1.0, (W, H), (123.68, 116.78, 103.94), swapRB=True, crop=False) start = time.time() net.setInput(blob) (scores, geometry) = net.forward(layerNames) end = time.time() # show timing information on text prediction print("[INFO] text detection took {:.6f} seconds".format(end - start)) # grab the number of rows and columns from the scores volume, then # initialize our set of bounding box rectangles and corresponding # confidence scores (numRows, numCols) = scores.shape[2:4] rects = [] confidences = [] # loop over the number of rows for y in range(0, numRows): # extract the scores (probabilities), followed by the geometrical # data used to derive potential bounding box coordinates that # surround text scoresData = scores[0, 0, y] xData0 = geometry[0, 0, y] xData1 = geometry[0, 1, y] xData2 = geometry[0, 2, y] xData3 = geometry[0, 3, y] anglesData = geometry[0, 4, y] # loop over the number of columns for x in range(0, numCols): # if our score does not have sufficient probability, ignore it if scoresData[x] < 0.5: continue # compute the offset factor as our resulting feature maps will # be 4x smaller than the input image (offsetX, offsetY) = (x * 4.0, y * 4.0) # extract the rotation angle for the prediction and then # compute the sin and cosine angle = anglesData[x] cos = np.cos(angle) sin = np.sin(angle) # use the geometry volume to derive the width and height of # the bounding box h = xData0[x] + xData2[x] w = xData1[x] + xData3[x] # compute both the starting and ending (x, y)-coordinates for # the text prediction bounding box endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x])) endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x])) startX = int(endX - w) startY = int(endY - h) # add the bounding box coordinates and probability score to # our respective lists rects.append((startX, startY, endX, endY)) confidences.append(scoresData[x]) # apply non-maxima suppression to suppress weak, overlapping bounding # boxes boxes = non_max_suppression(np.array(rects), probs=confidences) list1=[] list2=[] list3=[] list4=[] # loop over the bounding boxes for (startX, startY, endX, endY) in boxes: # scale the bounding box coordinates based on the respective # ratios startX = int(startX * rW) startY = int(startY * rH) endX = int(endX * rW) endY = int(endY * rH) list1.append(startX) list2.append(startY) list3.append(endX) list4.append(endY) # draw the bounding box on the image # cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 2) s1=min(list1) print(s1) s2=min(list2) print(s2) # print(list3) e1=max(list3) print(e1) dic={} e2=max(list4) print(e2) q1=(s1,s2) q2=(e1,s2) q3=(s1,e2) q4=(e1,e2) screenCnt = np.array([[q2], [q4], [q3], [q1]]) # dic={"topLeft":q1,"topRight":q2,"bottomLeft":q3,"bottomRight":q4} # screenCnt = np.array([[TOP_RIGHT], [BOTTOM_RIGHT], [BOTTOM_LEFT], [TOP_LEFT]]) # return jsonify(dic) else: screenCnt = max(approx_contours, key=cv2.contourArea) return screenCnt.reshape(4, 2)
def get_contour(self, rescaled_image): MORPH = 9 CANNY = 84 HOUGH = 25 IM_HEIGHT, IM_WIDTH, _ = rescaled_image.shape gray = cv2.cvtColor(rescaled_image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7,7), 0) kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH)) dilated = cv2.dilate(gray, kernel) edged = cv2.Canny(dilated, 0, CANNY) test_corners = self.get_corners(edged) approx_contours = [] if len(test_corners) >= 4: quads = [] for quad in itertools.combinations(test_corners, 4): points = np.array(quad) points = transform.order_points(points) points = np.array([[p] for p in points], dtype = "int32") quads.append(points) # get top five quadrilaterals by area quads = sorted(quads, key=cv2.contourArea, reverse=True)[:5] # sort candidate quadrilaterals by their angle range, which helps remove outliers quads = sorted(quads, key=self.angle_range) approx = quads[0] if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) # for debugging: uncomment the code below to draw the corners and countour found # by get_corners() and overlay it on the image # cv2.drawContours(rescaled_image, [approx], -1, (20, 20, 255), 2) # plt.scatter(*zip(*test_corners)) # plt.imshow(rescaled_image) # plt.show() # also attempt to find contours directly from the edged image, which occasionally # produces better results (_, cnts, hierarchy) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5] # loop over the contours for c in cnts: # approximate the contour approx = cv2.approxPolyDP(c, 80, True) if self.is_valid_contour(approx, IM_WIDTH, IM_HEIGHT): approx_contours.append(approx) break # If we did not find any valid contours, just use the whole image if not approx_contours: TOP_RIGHT = (IM_WIDTH, 0) BOTTOM_RIGHT = (IM_WIDTH, IM_HEIGHT) BOTTOM_LEFT = (0, IM_HEIGHT) TOP_LEFT = (0, 0) screenCnt = np.array([[TOP_RIGHT], [BOTTOM_RIGHT], [BOTTOM_LEFT], [TOP_LEFT]]) else: screenCnt = max(approx_contours, key=cv2.contourArea) return screenCnt.reshape(4, 2)