Source code for dedoc.attachments_extractors.concrete_attachments_extractors.image_attachments_extractor
import os
import uuid
from typing import Dict, Iterable, List, Optional
from dedocutils.data_structures.bbox import BBox
from numpy import ndarray
from torch import Tensor
from dedoc.attachments_extractors.abstract_attachment_extractor import AbstractAttachmentsExtractor
from dedoc.data_structures.attached_file import AttachedFile
[docs]class ImageAttachmentsExtractor(AbstractAttachmentsExtractor):
"""
Extract attachments from image files.
"""
def __init__(self, *, config: Optional[dict] = None) -> None:
from dedoc.extensions import recognized_extensions, recognized_mimes
from dedoc.config import get_config
super().__init__(config=config, recognized_extensions=recognized_extensions.image_like_format, recognized_mimes=recognized_mimes.image_like_format)
self._classes = {
2, # Formula
6 # Picture
}
self._image_processor = None
self._model = None
model_path = os.path.join(get_config()["resources_path"], "layout_model")
if os.path.exists(model_path):
self._model_name = model_path
self.logger.info("Using locally saved layout analysis model")
else:
self._model_name = "docling-project/docling-layout-heron"
self.logger.info("Layout analysis model will be loaded from huggingface")
self._threshold = self.config.get("image_detection_threshold", 0.7)
def _predict(self, image: ndarray) -> Iterable[Dict[str, Tensor]]:
import torch
from transformers import RTDetrImageProcessor, RTDetrV2ForObjectDetection
if self._image_processor is None:
self._image_processor = RTDetrImageProcessor.from_pretrained(self._model_name)
if self._model is None:
self._model = RTDetrV2ForObjectDetection.from_pretrained(self._model_name)
inputs = self._image_processor(images=[image], return_tensors="pt")
with torch.no_grad():
outputs = self._model(**inputs)
results = self._image_processor.post_process_object_detection(outputs, target_sizes=torch.tensor([image.shape[:-1]]), threshold=self._threshold)
return results
[docs] def extract(self, file_path: str, parameters: Optional[dict] = None) -> List[AttachedFile]:
"""
Get attachments from the given image using a document layout analysis method https://huggingface.co/docling-project/docling-layout-heron.
Look to the :class:`~dedoc.attachments_extractors.AbstractAttachmentsExtractor` documentation to get the information about the methods' parameters.
"""
import cv2
import os
from dedoc.utils.parameter_utils import get_param_need_content_analysis, get_param_attachments_dir
from dedoc.utils.utils import get_unique_name
from dedoc.readers.pdf_reader.data_classes.tables.location import Location
from dedoc.readers.pdf_reader.data_classes.pdf_image_attachment import PdfImageAttachment
parameters = {} if parameters is None else parameters
tmpdir, filename = os.path.split(file_path)
attachments_dir = get_param_attachments_dir(parameters, tmpdir)
attachments = []
image = cv2.imread(file_path)
predictions = self._predict(image)
for prediction in predictions:
for label_id, box in zip(prediction["labels"], prediction["boxes"]):
if label_id.item() not in self._classes:
continue
box = [round(i) for i in box.tolist()]
x_top_left, x_bottom_right = max(0, box[0]), min(box[2], image.shape[1])
y_top_left, y_bottom_right = max(0, box[1]), min(box[3], image.shape[0])
part = image[y_top_left:y_bottom_right, x_top_left:x_bottom_right]
image_location = Location(page_number=0, bbox=BBox.from_two_points((x_top_left, y_top_left), (x_bottom_right, y_bottom_right)))
tmp_file_name = get_unique_name(filename)
tmp_file_path = os.path.join(attachments_dir, tmp_file_name)
cv2.imwrite(tmp_file_path, part)
image_attachment = PdfImageAttachment(
original_name=tmp_file_name,
tmp_file_path=tmp_file_path,
need_content_analysis=get_param_need_content_analysis(parameters),
uid=f"attach_{uuid.uuid4()}",
location=image_location
)
attachments.append(image_attachment)
return attachments