Spaces:
Runtime error
Runtime error
| # app.py | |
| import cv2 | |
| import numpy as np | |
| import pytesseract | |
| from PIL import Image | |
| from transformers import CLIPProcessor, CLIPModel | |
| import torch | |
| import os | |
| import uuid | |
| import gradio as gr | |
| # Try importing pptx; give an error message if unavailable | |
| try: | |
| from pptx import Presentation | |
| from pptx.util import Inches | |
| except ImportError: | |
| raise ImportError("Missing 'python-pptx'. Please install it using 'pip install python-pptx'") | |
| # Load CLIP | |
| clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") | |
| clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") | |
| # Optional: Update Tesseract path if needed | |
| # pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe" | |
| def match_shapes(img1, img2): | |
| def preprocess(img): | |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| return cv2.Canny(gray, 100, 200) | |
| c1 = preprocess(img1) | |
| c2 = preprocess(img2) | |
| contours1, _ = cv2.findContours(c1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
| contours2, _ = cv2.findContours(c2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
| matches = 0 | |
| for cnt1 in contours1: | |
| for cnt2 in contours2: | |
| score = cv2.matchShapes(cnt1, cnt2, 1, 0.0) | |
| if score < 0.2: | |
| matches += 1 | |
| break | |
| score = matches / max(len(contours1), 1) | |
| return round(score * 100, 2), contours1, contours2 | |
| def extract_text(img): | |
| return pytesseract.image_to_string(img).strip() | |
| def compare_text(text1, text2): | |
| t1_words = set(text1.lower().split()) | |
| t2_words = set(text2.lower().split()) | |
| if not t1_words or not t2_words: | |
| return 0 | |
| return round(len(t1_words & t2_words) / len(t1_words | t2_words) * 100, 2) | |
| def semantic_score(img1, img2): | |
| inputs = clip_processor(images=[img1, img2], return_tensors="pt") | |
| outputs = clip_model.get_image_features(**inputs) | |
| sim = torch.nn.functional.cosine_similarity(outputs[0][0], outputs[0][1], dim=0) | |
| return round(float(sim.item()) * 100, 2) | |
| def draw_comparison(img1, img2, contours1, contours2): | |
| out1 = img1.copy() | |
| out2 = img2.copy() | |
| for cnt in contours1: | |
| cv2.drawContours(out1, [cnt], -1, (0, 0, 255), 2) | |
| for cnt in contours2: | |
| cv2.drawContours(out2, [cnt], -1, (0, 255, 0), 2) | |
| combined = np.hstack((out1, out2)) | |
| return combined | |
| def generate_ppt(source_img_path, comp_img_path, comparison_img, shape_score, text_score, semantic_score): | |
| prs = Presentation() | |
| slide = prs.slides.add_slide(prs.slide_layouts[5]) | |
| slide.shapes.title.text = "Image Comparison Report" | |
| slide1 = prs.slides.add_slide(prs.slide_layouts[5]) | |
| slide1.shapes.title.text = "Input Images" | |
| slide1.shapes.add_picture(source_img_path, Inches(0.5), Inches(1), width=Inches(4)) | |
| slide1.shapes.add_picture(comp_img_path, Inches(5), Inches(1), width=Inches(4)) | |
| slide2 = prs.slides.add_slide(prs.slide_layouts[5]) | |
| slide2.shapes.title.text = "Comparison Scores" | |
| scores = f"""Shape Score: {shape_score}% (Rating: {int(shape_score // 20)}/5)\nText Score: {text_score}% (Rating: {int(text_score // 20)}/5)\nSemantic Score: {semantic_score}% (Rating: {int(semantic_score // 20)}/5)""" | |
| tf = slide2.shapes.add_textbox(Inches(1), Inches(1), Inches(8), Inches(3)).text_frame | |
| tf.text = scores | |
| slide3 = prs.slides.add_slide(prs.slide_layouts[5]) | |
| slide3.shapes.title.text = "Visual Comparison" | |
| fname = f"compare_{uuid.uuid4().hex[:6]}.png" | |
| cv2.imwrite(fname, comparison_img) | |
| slide3.shapes.add_picture(fname, Inches(1), Inches(1), width=Inches(7)) | |
| output_ppt = f"comparison_report_{uuid.uuid4().hex[:6]}.pptx" | |
| prs.save(output_ppt) | |
| return output_ppt | |
| def process_images(img1_np, img2_np): | |
| cv2.imwrite("source.png", img1_np) | |
| cv2.imwrite("target.png", img2_np) | |
| img1 = cv2.imread("source.png") | |
| img2 = cv2.imread("target.png") | |
| shape_score, cnt1, cnt2 = match_shapes(img1, img2) | |
| text_score = compare_text(extract_text(img1), extract_text(img2)) | |
| sem_score = semantic_score(Image.fromarray(img1_np), Image.fromarray(img2_np)) | |
| compare_img = draw_comparison(img1, img2, cnt1, cnt2) | |
| ppt_path = generate_ppt("source.png", "target.png", compare_img, shape_score, text_score, sem_score) | |
| return ppt_path | |
| def gradio_interface(img1, img2): | |
| ppt = process_images(np.array(img1), np.array(img2)) | |
| return ppt | |
| demo = gr.Interface( | |
| fn=gradio_interface, | |
| inputs=[gr.Image(type="pil"), gr.Image(type="pil")], | |
| outputs=gr.File(label="Download PPT Report"), | |
| title="Smart CAD Image Comparator", | |
| description="Upload two technical/CAD images to compare shapes, text, dimensions, and get a detailed PPT report." | |
| ) | |
| demo.launch() | |