import fitz # PyMuPDF import cv2 import numpy as np import pandas as pd import os import uuid import pypdfium2 as pdfium from PIL import Image def convert2img(path): pdf = pdfium.PdfDocument(path) page = pdf.get_page(0) pil_image = page.render().to_pil() pl1=np.array(pil_image) img = cv2.cvtColor(pl1, cv2.COLOR_RGB2BGR) return img def save_image(img): filename = f"{uuid.uuid4().hex}.png" path = os.path.join("/tmp", filename) cv2.imwrite(path, img) return filename def threshold(imgResult3): #gaus4 = cv2.GaussianBlur(imgResult3, (3,3),9) blur = cv2.blur(imgResult3,(7,7)) gray4 = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY) outsu4 = cv2.threshold(gray4, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] return outsu4 def get_columns_info(outsu4, img): mask_clmns = np.ones(img.shape[:2], dtype="uint8") * 255 mask_walls = np.ones(img.shape[:2], dtype="uint8") * 255 contours, hierarchy = cv2.findContours(image=outsu4, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) p = [] #to save points of each contour for i, cnt in enumerate(contours): M = cv2.moments(cnt) if M['m00'] != 0.0: x1 = int(M['m10']/M['m00']) y1 = int(M['m01']/M['m00']) area = cv2.contourArea(cnt) if area > (881.0*2): perimeter = cv2.arcLength(cnt,True) #print(perimeter) cv2.drawContours(mask_walls, [cnt], -1, 0, -1) if area < (881.0 * 2) and area > 90: # maybe make it area < (881.0 * 1.5) p.append((x1,y1)) #print(area) cv2.drawContours(mask_clmns, [cnt], -1, 0, -1) return p, mask_clmns, mask_walls def get_text_from_pdf(input_pdf_path): pdf_document = fitz.open(input_pdf_path) results = [] for page_num in range(pdf_document.page_count): page = pdf_document[page_num] width, height = page.rect.width, page.rect.height # Get page dimensions text_instances = [word for word in page.get_text("words") if word[4].startswith(("C", "c")) and len(word[4]) <= 5] page.apply_redactions() return text_instances def calculate_midpoint(x1,y1,x2,y2): xm = int((x1 + x2) / 2) ym = int((y1 + y2) / 2) return (xm, ym) def getTextsPoints(x): point_list = [] pt_clm = {} for h in x: #point_list.append(calculate_midpoint(h[1],h[0],h[3],h[2])) #pt_clm[calculate_midpoint(h[1],h[0],h[3],h[2])] = h[4] point_list.append(calculate_midpoint(h[0],h[1],h[2],h[3])) pt_clm[calculate_midpoint(h[0],h[1],h[2],h[3])] = h[4] return point_list, pt_clm def fix_90_ky_val(pt_clm, derotationMatrix): new_derotated = {} for ky in pt_clm: pts = fitz.Point(ky[0], ky[1]) * derotationMatrix new_ky = ((int(pts.y),int(pts.x))) new_derotated[new_ky] = pt_clm[ky] return new_derotated def distance(point1, point2): x1, y1 = point1 x2, y2 = point2 return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) def getNearestText(point_list, p): nearbyy = [] selected_clm_point = [] #save the clmn for drawing cirlce on it dis = [] txt_clmn = [] for i in range(len(p)): nearest_point = min(point_list, key=lambda point: distance(point, p[i])) dist = distance(nearest_point, p[i]) dis.append(dist) #if dist < 10: nearbyy.append(nearest_point) selected_clm_point.append(p[i]) txt_clmn.append((nearest_point, p[i])) return nearbyy, selected_clm_point, txt_clmn def fix_rotation_90(pc_coordinates, derotationMatrix): coor = [] for coordinate in pc_coordinates: pts = fitz.Point(coordinate[0], coordinate[1]) * derotationMatrix coor.append((int(pts.y),int(pts.x))) return coor def color_groups(txtpts_ky_vlu): import random unique_labels = list(set(txtpts_ky_vlu.values())) def generate_rgb(): return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # RGB tuple key_colors = {key: generate_rgb() for key in unique_labels} # Assign a unique RGB color to each key return key_colors def getColumnsTypesKeyValue(nearbyy, pt_clm): words = [] for i in range(len(nearbyy)): words.append(pt_clm[nearbyy[i]]) return words def generate_legend(found_tuple): word_freq = {} for word in found_tuple: if word in word_freq: word_freq[word] += 1 else: word_freq[word] = 1 data = word_freq df = pd.DataFrame(data.items(), columns=['Column Type', 'Count']) return df def get_drawing_info(txt_clmn,txtpts_ky_vlu,key_colors): #Search for each word in the txt_clmn to get the word associated to it huge_list_clmn_clr_loc = [] for text_location, column_location in txt_clmn: word = txtpts_ky_vlu[text_location] huge_list_clmn_clr_loc.append((text_location, column_location, word, key_colors[word])) return huge_list_clmn_clr_loc #text_location, column_location, word, color def get_columns_info2(outsu4, img): mask_clmns = np.ones(img.shape[:2], dtype="uint8") * 255 mask_walls = np.ones(img.shape[:2], dtype="uint8") * 255 contours, hierarchy = cv2.findContours(image=outsu4, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE) p_column = [] #to save midpoints of each column p_wall = [] #to save midpoints of each wall wall_contour = [] all_points = [] wall_mid_and_full = {} for i, cnt in enumerate(contours): M = cv2.moments(cnt) if M['m00'] != 0.0: x1 = int(M['m10']/M['m00']) y1 = int(M['m01']/M['m00']) area = cv2.contourArea(cnt) if area > (881.0): perimeter = cv2.arcLength(cnt,True) p_wall.append((x1,y1)) #print(perimeter) cv2.drawContours(mask_walls, [cnt], -1, 0, -1) wall_contour.append(cnt) all_points.append((x1,y1)) wall_mid_and_full[(x1, y1)] = cnt if area < (881.0 * 2) and area > 90: # maybe make it area < (881.0 * 1.5) all_points.append((x1,y1)) p_column.append((x1,y1)) #print(area) cv2.drawContours(mask_clmns, [cnt], -1, 0, -1) wall_mid_and_full[(x1, y1)] = cnt return p_column, p_wall, mask_clmns, mask_walls, wall_contour, all_points, wall_mid_and_full def get_all_wall_points(wall_contours): all_contours = [] for cnt in wall_contours: contour_points = [(int(point[0][0]), int(point[0][1])) for point in cnt] all_contours.append(contour_points) return all_contours def get_text_wall_text(input_pdf_path): pdf_document = fitz.open(input_pdf_path) results = [] for page_num in range(pdf_document.page_count): page = pdf_document[page_num] width, height = page.rect.width, page.rect.height text_instances = [word for word in page.get_text("words") if word[4].startswith(("w", "W")) and len(word[4]) <= 5] page.apply_redactions() return text_instances import math def distance(p1, p2): return math.hypot(p1[0] - p2[0], p1[1] - p2[1]) def assign_walls_to_texts(text_locations, wall_locations, threshold=55): matched_texts = [] matched_walls = [] text_wall_pairs = [] for text in text_locations: nearest_wall = min(wall_locations, key=lambda wall: distance(wall, text)) dist = distance(nearest_wall, text) print(f"Text {text} -> Nearest wall {nearest_wall}, Distance: {dist:.2f}") if dist < threshold: matched_texts.append(text) matched_walls.append(nearest_wall) text_wall_pairs.append((text, nearest_wall)) return matched_texts, matched_walls, text_wall_pairs