463 lines
17 KiB
Plaintext
463 lines
17 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Name: Pillow\n",
|
|
"Version: 9.5.0\n",
|
|
"Summary: Python Imaging Library (Fork)\n",
|
|
"Home-page: https://python-pillow.org\n",
|
|
"Author: Jeffrey A. Clark (Alex)\n",
|
|
"Author-email: aclark@aclark.net\n",
|
|
"License: HPND\n",
|
|
"Location: /opt/homebrew/lib/python3.11/site-packages\n",
|
|
"Requires: \n",
|
|
"Required-by: basicsr, blendmodes, clean-fid, controlnet-aux, diffusers, facexlib, fvcore, gradio, imageio, label-studio-converter, matplotlib, min-dalle, python-pptx, realesrgan, refiners, reportlab, scikit-image, streamlit, torchvision, unstructured\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"!pip show Pillow"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"(14435, 1272)\n",
|
|
"<PIL.Image.Image image mode=RGBA size=362x626 at 0x1055B5630> (7571, 639, 7933, 1265)\n",
|
|
"<PIL.Image.Image image mode=RGBA size=323x424 at 0x1055B6B00> (9555, 736, 9878, 1160)\n",
|
|
"<PIL.Image.Image image mode=RGBA size=195x493 at 0x1055B6C20> (10789, 620, 10984, 1113)\n",
|
|
"<PIL.Image.Image image mode=RGBA size=309x581 at 0x1055B6D40> (12234, 691, 12543, 1272)\n",
|
|
"<PIL.Image.Image image mode=RGBA size=512x463 at 0x1055B6D10> (12897, 535, 13409, 998)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"from PIL import Image\n",
|
|
"from IPython.display import display\n",
|
|
"\n",
|
|
"MIN_SIZE = 10\n",
|
|
"\n",
|
|
"\n",
|
|
"# returns an array of images and their positions in the original image\n",
|
|
"def split_image_vertically(\n",
|
|
" img: Image.Image, pos: tuple[int, int, int, int] = None, rec=0\n",
|
|
"):\n",
|
|
" # find first vertical fully transparent line\n",
|
|
"\n",
|
|
" img_box = img.getbbox()\n",
|
|
" if img_box is None or img.size <= (MIN_SIZE, MIN_SIZE): # image is empty\n",
|
|
" return []\n",
|
|
"\n",
|
|
" img = img.crop(img_box)\n",
|
|
"\n",
|
|
" position = pos if pos is not None else (0, 0, img.width, img.height)\n",
|
|
" position = (\n",
|
|
" position[0] + img_box[0],\n",
|
|
" position[1] + img_box[1],\n",
|
|
" position[0] + img_box[2],\n",
|
|
" position[1] + img_box[3],\n",
|
|
" ) # Add the offset of the cropped image\n",
|
|
"\n",
|
|
" # print(position, rec)\n",
|
|
" # display(img)\n",
|
|
"\n",
|
|
" for x in range(img.width):\n",
|
|
" if all(img.getpixel((x, y))[3] == 0 for y in range(img.height)):\n",
|
|
" break\n",
|
|
" if x == img.width - 1: # no transparent line found\n",
|
|
" return [(img, position)]\n",
|
|
"\n",
|
|
" left = img.crop((0, 0, x, img.height))\n",
|
|
"\n",
|
|
" left_position = (\n",
|
|
" position[0],\n",
|
|
" position[1],\n",
|
|
" position[0] + x,\n",
|
|
" position[3],\n",
|
|
" )\n",
|
|
"\n",
|
|
" right = img.crop((x + 1, 0, img.width, img.height))\n",
|
|
" right_position = (\n",
|
|
" position[0] + x + 1,\n",
|
|
" position[1],\n",
|
|
" position[2] - x + 1,\n",
|
|
" position[3],\n",
|
|
" )\n",
|
|
"\n",
|
|
" res = (split_image_vertically(left, left_position, rec + 1)) + (\n",
|
|
" split_image_vertically(right, right_position, rec + 1)\n",
|
|
" )\n",
|
|
"\n",
|
|
" return res\n",
|
|
"\n",
|
|
"\n",
|
|
"def display_images(images: list):\n",
|
|
" for img, pos in images:\n",
|
|
" # img.show()\n",
|
|
" print(img, pos)\n",
|
|
"\n",
|
|
"\n",
|
|
"test = Image.open(\"sources/main2/8plan.png\")\n",
|
|
"\n",
|
|
"print(test.size)\n",
|
|
"\n",
|
|
"display_images(split_image_vertically(test))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import json\n",
|
|
"import os\n",
|
|
"from typing import Union\n",
|
|
"from PIL.Image import Image, open as open_image, Resampling\n",
|
|
"from pathlib import Path\n",
|
|
"import math\n",
|
|
"\n",
|
|
"MIN_SIZE = 20\n",
|
|
"\n",
|
|
"EXTENSION = \"webp\"\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_images(folder):\n",
|
|
" images = []\n",
|
|
" for root, dirs, files in os.walk(folder):\n",
|
|
" for file in files:\n",
|
|
" if file.endswith(\".png\") and not file.startswith(\"._\"):\n",
|
|
" images.append(os.path.join(root, file))\n",
|
|
" return images\n",
|
|
"\n",
|
|
"\n",
|
|
"def crop_and_get_position(img: Image) -> Union[Image, tuple]:\n",
|
|
" img_box = img.getbbox()\n",
|
|
" cropped = img.crop(img_box)\n",
|
|
" return cropped, img_box\n",
|
|
"\n",
|
|
"\n",
|
|
"def resize(img: Image, ratio) -> Image:\n",
|
|
" img.thumbnail((int(img.width * ratio), int(img.height * ratio)), Resampling.BICUBIC)\n",
|
|
" return img\n",
|
|
"\n",
|
|
"\n",
|
|
"def blackout_transparent(img: Image) -> Image:\n",
|
|
" img = img.convert(\"RGBA\")\n",
|
|
" data = img.getdata()\n",
|
|
"\n",
|
|
" new_data = []\n",
|
|
" for item in data:\n",
|
|
" if item[3] == 0:\n",
|
|
" new_data.append((0, 0, 0, 0))\n",
|
|
" else:\n",
|
|
" new_data.append(item)\n",
|
|
"\n",
|
|
" img.putdata(new_data)\n",
|
|
" return img\n",
|
|
"\n",
|
|
"\n",
|
|
"def process_dir(path, output_folder, config_path, ratio=1.0, split=True):\n",
|
|
" image_paths = get_images(path)\n",
|
|
"\n",
|
|
" if not os.path.exists(output_folder):\n",
|
|
" os.makedirs(output_folder, exist_ok=True)\n",
|
|
"\n",
|
|
" if os.path.exists(config_path):\n",
|
|
" with open(config_path, \"r\") as f:\n",
|
|
" config = json.load(f)\n",
|
|
" else:\n",
|
|
" config = {}\n",
|
|
"\n",
|
|
" fullWidth = int(math.ceil(open_image(image_paths[0]).width * ratio))\n",
|
|
" fullHeight = int(math.ceil(open_image(image_paths[0]).height * ratio))\n",
|
|
"\n",
|
|
" resImages = config.get(\"images\", {})\n",
|
|
"\n",
|
|
" for image_path in image_paths:\n",
|
|
" print(\"Processing\", image_path, \"...\")\n",
|
|
" img = open_image(image_path)\n",
|
|
"\n",
|
|
" if ratio != 1.0:\n",
|
|
" img = resize(img, ratio)\n",
|
|
"\n",
|
|
" img = blackout_transparent(img)\n",
|
|
"\n",
|
|
" if split:\n",
|
|
" allImages = split_image_vertically(img, (0, 0, img.width, img.height))\n",
|
|
" else:\n",
|
|
" allImages = [crop_and_get_position(img)]\n",
|
|
"\n",
|
|
" print(\"Split into\", len(allImages), \"images\")\n",
|
|
" i = 0\n",
|
|
" for img, box in allImages:\n",
|
|
" if img.height < MIN_SIZE or img.width < MIN_SIZE or box is None:\n",
|
|
" continue\n",
|
|
"\n",
|
|
" image_p = Path(image_path)\n",
|
|
" image_name = image_p.stem + (\n",
|
|
" f\"_{i}.{EXTENSION}\" if len(allImages) > 1 else f\".{EXTENSION}\"\n",
|
|
" )\n",
|
|
" subFolder = os.path.dirname(image_path.replace(path, \"\"))\n",
|
|
" output_path = os.path.join(output_folder, subFolder, image_name)\n",
|
|
" print(\"Saving\", output_path, \"...\")\n",
|
|
" if not os.path.exists(os.path.dirname(output_path)):\n",
|
|
" os.makedirs(os.path.dirname(output_path), exist_ok=True)\n",
|
|
" img.save(output_path, EXTENSION)\n",
|
|
"\n",
|
|
" if output_path not in resImages:\n",
|
|
" resImages[output_path] = {}\n",
|
|
" resImages[output_path][\"position\"] = box\n",
|
|
"\n",
|
|
" i += 1\n",
|
|
"\n",
|
|
" config[\"images\"] = resImages\n",
|
|
" config[\"fullWidth\"] = fullWidth\n",
|
|
" config[\"fullHeight\"] = fullHeight\n",
|
|
"\n",
|
|
" with open(config_path, \"w\") as f:\n",
|
|
" f.write(json.dumps(config, indent=2))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = \"sources/main2/\"\n",
|
|
"config_path = \"public/assets/main-scene-cropped-config.json\"\n",
|
|
"\n",
|
|
"output_folder = \"public/assets/main\"\n",
|
|
"\n",
|
|
"process_dir(path, output_folder, config_path, 0.5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = \"sources/school-images/\"\n",
|
|
"config_path = \"public/assets/school-cropped-config.json\"\n",
|
|
"\n",
|
|
"output_folder = \"public/assets/school-cropped\"\n",
|
|
"\n",
|
|
"process_dir(path, output_folder, config_path, split=False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_tabac.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_tabac.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/3plan_br_zoom_lampe_off.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/3plan_br_zoom_lampe_off.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/ciel_br_zoom_nuit.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/ciel_br_zoom_nuit.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/arriereplan_br_zoom_nuit.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/arriereplan_br_zoom_nuit.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/3plan_br_zoom_boule et bill.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/3plan_br_zoom_boule et bill.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_tabac_megot.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_tabac_megot.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/7plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/7plan_br_zoom.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/3plan_br_zoom_livre.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/3plan_br_zoom_livre.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/6plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/6plan_br_zoom.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/2plan_br_zoom_rufius.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/2plan_br_zoom_rufius.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/5plan_br_zoom_portrait.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/5plan_br_zoom_portrait.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/arriereplan_br_zoom_jour.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/arriereplan_br_zoom_jour.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_raquette.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_raquette.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/2plan_br_zoom_raquette_balle.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/2plan_br_zoom_raquette_balle.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/4plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/4plan_br_zoom.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/3plan_br_zoom_lampe_on.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/3plan_br_zoom_lampe_on.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/ciel_br_zoom_jour.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/ciel_br_zoom_jour.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_patte01.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_patte01.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/2plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/2plan_br_zoom.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_patte02.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_patte02.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_patte03.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_patte03.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/2plan_br_zoom_brutus.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/2plan_br_zoom_brutus.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/br_zoom_total.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/br_zoom_total.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/1plan_br_zoom_patte04.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/1plan_br_zoom_patte04.webp ...\n",
|
|
"Processing sources/brutus et rufius_vs01/5plan_br_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/brutus-rufius/5plan_br_zoom.webp ...\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"path = \"sources/brutus et rufius_vs01/\"\n",
|
|
"config_path = \"public/assets/brutus-rufius-scene-config.json\"\n",
|
|
"\n",
|
|
"output_folder = \"public/assets/brutus-rufius\"\n",
|
|
"\n",
|
|
"process_dir(path, output_folder, config_path, split=False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_asperge.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_asperge.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/arrierearriere_ag_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/arrierearriere_ag_zoom.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_mais.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_mais.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/01plan_ag.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/01plan_ag.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/2plan_ag_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/2plan_ag_zoom.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_aubergine.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_aubergine.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_brocoli.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_brocoli.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/1plan_ag.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/1plan_ag.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_patate.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_patate.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_marron.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_marron.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/arriereplan_ag_zoom.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/arriereplan_ag_zoom.webp ...\n",
|
|
"Processing sources/ag des leguminaires_vs01/3plan_ag_zoom_celeri.png ...\n",
|
|
"Split into 1 images\n",
|
|
"Saving public/assets/ag/3plan_ag_zoom_celeri.webp ...\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"path = \"sources/ag des leguminaires_vs01/\"\n",
|
|
"config_path = \"public/assets/ag-scene-config.json\"\n",
|
|
"\n",
|
|
"output_folder = \"public/assets/ag\"\n",
|
|
"\n",
|
|
"process_dir(path, output_folder, config_path, split=False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = \"PAN_papier decoupe_vs01/\"\n",
|
|
"config_path = \"public/assets/main-scene-config.json\"\n",
|
|
"\n",
|
|
"output_folder = \"public/assets/main\"\n",
|
|
"\n",
|
|
"process_dir(path, output_folder, config_path, 0.5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.10.13"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|