{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":113558,"databundleVersionId":14878066,"isSourceIdPinned":false}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -q transformers accelerate pillow opencv-python markdown\n!pip install -q chandra-ocr[hf]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T05:58:23.681387Z","iopub.execute_input":"2026-04-29T05:58:23.682126Z","iopub.status.idle":"2026-04-29T05:58:44.446145Z","shell.execute_reply.started":"2026-04-29T05:58:23.682093Z","shell.execute_reply":"2026-04-29T05:58:44.445416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from transformers import AutoModelForImageTextToText, AutoProcessor\nfrom chandra.model.hf import generate_hf\nfrom chandra.model.schema import BatchInputItem\nfrom chandra.output import parse_markdown\n\nimport torch\nimport cv2\nimport numpy as np\nfrom PIL import Image\n\nfrom IPython.display import display, HTML\nimport markdown as md\nimport re","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T05:58:44.447683Z","iopub.execute_input":"2026-04-29T05:58:44.448391Z","iopub.status.idle":"2026-04-29T05:59:05.763422Z","shell.execute_reply.started":"2026-04-29T05:58:44.448362Z","shell.execute_reply":"2026-04-29T05:59:05.762838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = AutoModelForImageTextToText.from_pretrained(\n    \"datalab-to/chandra-ocr-2\",\n    torch_dtype = torch.float16,   \n    device_map = \"auto\",\n    low_cpu_mem_usage = True\n)\n\nmodel.eval()\n\nprocessor = AutoProcessor.from_pretrained(\"datalab-to/chandra-ocr-2\")\nprocessor.tokenizer.padding_side = \"left\"\n\nmodel.processor = processor","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T05:59:05.764276Z","iopub.execute_input":"2026-04-29T05:59:05.764851Z","iopub.status.idle":"2026-04-29T06:00:07.391506Z","shell.execute_reply.started":"2026-04-29T05:59:05.764824Z","shell.execute_reply":"2026-04-29T06:00:07.390930Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_PATH = \"/kaggle/input/competitions/recodai-luc-scientific-image-forgery-detection/test_images/45.png\"\n\nimage = Image.open(IMAGE_PATH)\n\nimage.thumbnail((1024, 1024))\n\ndisplay(image)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T06:00:07.393037Z","iopub.execute_input":"2026-04-29T06:00:07.393259Z","iopub.status.idle":"2026-04-29T06:00:07.535159Z","shell.execute_reply.started":"2026-04-29T06:00:07.393237Z","shell.execute_reply":"2026-04-29T06:00:07.534376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def detect_panels(image_path):\n    img = cv2.imread(image_path)\n    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n\n    _, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)\n\n    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n\n    panels = []\n\n    for cnt in contours:\n        x, y, w, h = cv2.boundingRect(cnt)\n\n        if w > 120 and h > 120:\n            panel = img[y:y + h, x:x + w]\n            panels.append((x, y, w, h, panel))\n\n    panels = sorted(panels, key=lambda x: (x[1], x[0]))\n\n    return panels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T06:00:07.536073Z","iopub.execute_input":"2026-04-29T06:00:07.536388Z","iopub.status.idle":"2026-04-29T06:00:07.542055Z","shell.execute_reply.started":"2026-04-29T06:00:07.536363Z","shell.execute_reply":"2026-04-29T06:00:07.541330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"panels = detect_panels(IMAGE_PATH)\n\npanel_images = []\n\nfor i, (x, y, w, h, panel) in enumerate(panels):\n    pil_img = Image.fromarray(cv2.cvtColor(panel, cv2.COLOR_BGR2RGB))\n    \n    pil_img.thumbnail((768, 768))\n    \n    panel_images.append(pil_img)\n    \n    print(f\"Panel {i + 1}\")\n    display(pil_img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T06:00:07.542944Z","iopub.execute_input":"2026-04-29T06:00:07.543226Z","iopub.status.idle":"2026-04-29T06:00:07.675386Z","shell.execute_reply.started":"2026-04-29T06:00:07.543194Z","shell.execute_reply":"2026-04-29T06:00:07.674636Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_outputs = []\n\nfor i, panel_img in enumerate(panel_images):\n\n    batch = [\n        BatchInputItem(\n            image = panel_img,\n            prompt_type = \"ocr_layout\"\n        )\n    ]\n\n    result = generate_hf(\n        batch,\n        model,\n        max_output_tokens = 512\n    )[0]\n\n    markdown_text = parse_markdown(result.raw)\n\n    markdown_text = re.sub(r'!\\[.*?\\]\\(.*?\\)', '', markdown_text)\n\n    markdown_text = re.sub(r\"<math>(.*?)</math>\", r\"\\1\", markdown_text)\n    markdown_text = markdown_text.replace(\"\\\\beta\", \"β\")\n\n    all_outputs.append(\n        {\n            \"panel\": f\"Panel {i+1}\",\n            \"markdown\": markdown_text\n        }\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T06:00:07.676428Z","iopub.execute_input":"2026-04-29T06:00:07.676773Z","iopub.status.idle":"2026-04-29T06:01:22.703741Z","shell.execute_reply.started":"2026-04-29T06:00:07.676736Z","shell.execute_reply":"2026-04-29T06:01:22.703136Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"html_blocks = []\n\nfor item in all_outputs:\n    html = md.markdown(item[\"markdown\"], extensions = [\"tables\"])\n\n    block = f\"\"\"\n        <div style=\"margin-bottom:40px;\">\n            <h2>{item['panel']}</h2>\n            {html}\n        </div>\n        <hr>\n    \"\"\"\n\n    html_blocks.append(block)\n\ndisplay(\n    HTML(\n        f\"\"\"\n            <div style=\"\n                font-family: Arial, sans-serif;\n                line-height:1.7;\n                max-width: 900px;\n                margin: auto;\n            \">\n            {''.join(html_blocks)}\n            </div>\n        \"\"\"\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-29T06:01:22.704731Z","iopub.execute_input":"2026-04-29T06:01:22.705077Z","iopub.status.idle":"2026-04-29T06:01:22.765293Z","shell.execute_reply.started":"2026-04-29T06:01:22.705037Z","shell.execute_reply":"2026-04-29T06:01:22.764766Z"}},"outputs":[],"execution_count":null}]}