From eaafa5e291acf4342a973d0428deb8160008e45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 16:58:04 -0300 Subject: [PATCH 1/9] Example notebook for random text generation --- text_generation/example.ipynb | 195 ++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 text_generation/example.ipynb diff --git a/text_generation/example.ipynb b/text_generation/example.ipynb new file mode 100644 index 0000000..6729dc9 --- /dev/null +++ b/text_generation/example.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image, ImageDraw, ImageFont\n", + "import random\n", + "import string\n", + "from matplotlib import font_manager\n", + "\n", + "def generar_imagen_con_palabras_rndfont(texto, img_shape, tamano_letra, color_texto, fondo_color, ruta_guardado):\n", + " # Create white plain image\n", + " imagen = Image.new(\"RGB\", img_shape, fondo_color)\n", + " dibujo = ImageDraw.Draw(imagen)\n", + "\n", + " # Compute amount of lines depending on image shape and number of characters\n", + " N_total = len(texto)\n", + " N_lines = N_total//img_shape[1]\n", + " N_horizontal = img_shape[0]//(tamano_letra)\n", + "\n", + " # Get system font types\n", + " system_fonts = font_manager.get_fontconfig_fonts()\n", + " # Filter out some non-readable fonts\n", + " ttf_fonts = [font for font in system_fonts if ((\".ttf\" in font) and (\"lohit\" not in font) and (\"kacst\" not in font)) and (\"Navilu\" not in font) and (\"telu\" not in font) and (\"lyx\" not in font) and (\"malayalam\" not in font) and (\"tlwg\" not in font) and (\"samyak\" not in font) and (\"droid\" not in font) and (\"kalapi\" not in font) and (\"openoffice\" not in font) and (\"orya\" not in font)]\n", + "\n", + " # Write over image one font per line\n", + " for iter in range(N_lines):\n", + " rnd_font_index = random.randint(0,len(ttf_fonts)-1)\n", + " random_font = ttf_fonts[rnd_font_index]\n", + " # print(f\"Font N {iter}: {random_font}\")\n", + "\n", + " # Load text font and set size\n", + " fuente = ImageFont.truetype(font=random_font, size=tamano_letra)\n", + " # Get line text\n", + " texto_linea = texto[iter * N_horizontal : (iter+1) * N_horizontal]\n", + "\n", + " # Adjust text position\n", + " posicion_texto = ((imagen.width - fuente.getsize(texto_linea)[0]) // 2, \n", + " int(1.5* iter * tamano_letra))\n", + "\n", + " # Write text\n", + " dibujo.text(posicion_texto, texto_linea, font=fuente, fill=color_texto)\n", + "\n", + " # Save image\n", + " imagen.save(ruta_guardado)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 210, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "147\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_28967/2165524556.py:1: MatplotlibDeprecationWarning: \n", + "The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.\n", + " system_fonts = font_manager.get_fontconfig_fonts()#findSystemFonts(fontpaths=None, fontext='ttf')\n" + ] + } + ], + "source": [ + "system_fonts = font_manager.get_fontconfig_fonts()#findSystemFonts(fontpaths=None, fontext='ttf')\n", + "ttf_fonts = [font for font in system_fonts if ((\".ttf\" in font) and (\"lohit\" not in font) and (\"kacst\" not in font)) and (\"Navilu\" not in font) and (\"telu\" not in font) and (\"lyx\" not in font) and (\"malayalam\" not in font) and (\"tlwg\" not in font) and (\"samyak\" not in font) and (\"droid\" not in font) and (\"kalapi\" not in font) and (\"openoffice\" not in font) and (\"orya\" not in font)]\n", + "print(len(ttf_fonts))" + ] + }, + { + "cell_type": "code", + "execution_count": 209, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "33\n", + "7\n", + "Font N 0: /usr/share/fonts/truetype/liberation2/LiberationSans-BoldItalic.ttf\n", + "Font N 1: /usr/share/fonts/truetype/liberation/LiberationSans-Italic.ttf\n", + "Font N 2: /usr/share/fonts/truetype/ubuntu/Ubuntu-C.ttf\n", + "Font N 3: /usr/share/fonts/truetype/ttf-bitstream-vera/VeraBI.ttf\n", + "Font N 4: /usr/share/fonts/truetype/ubuntu/UbuntuMono-R.ttf\n", + "Font N 5: /usr/share/fonts/truetype/lato/Lato-LightItalic.ttf\n", + "Font N 6: /usr/share/fonts/truetype/liberation2/LiberationSans-BoldItalic.ttf\n", + "Font N 7: /usr/share/fonts/truetype/liberation2/LiberationSans-Bold.ttf\n", + "Font N 8: /usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf\n", + "Font N 9: /usr/share/fonts/truetype/fonts-gujr-extra/Rekha.ttf\n", + "Font N 10: /usr/share/fonts/truetype/fonts-beng-extra/MuktiNarrowBold.ttf\n", + "Font N 11: /usr/share/fonts/truetype/tibetan-machine/TibetanMachineUni.ttf\n", + "Font N 12: /usr/share/fonts/truetype/Sahadeva/sahadeva.ttf\n", + "Font N 13: /usr/share/fonts/truetype/lato/Lato-Heavy.ttf\n", + "Font N 14: /usr/share/fonts/truetype/padauk/PadaukBook-Bold.ttf\n", + "Font N 15: /usr/share/fonts/truetype/padauk/Padauk-Bold.ttf\n", + "Font N 16: /usr/share/fonts/truetype/lato/Lato-Regular.ttf\n", + "Font N 17: /usr/share/fonts/truetype/pagul/Pagul.ttf\n", + "Font N 18: /usr/share/fonts/truetype/fonts-yrsa-rasa/Yrsa-SemiBold.ttf\n", + "Font N 19: /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf\n", + "Font N 20: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", + "Font N 21: /usr/share/fonts/truetype/fonts-beng-extra/JamrulNormal.ttf\n", + "Font N 22: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", + "Font N 23: /usr/share/fonts/truetype/lato/Lato-Italic.ttf\n", + "Font N 24: /usr/share/fonts/truetype/liberation2/LiberationSerif-Regular.ttf\n", + "Font N 25: /usr/share/fonts/truetype/ubuntu/Ubuntu-L.ttf\n", + "Font N 26: /usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf\n", + "Font N 27: /usr/share/fonts/truetype/dejavu/DejaVuSerifCondensed-Bold.ttf\n", + "Font N 28: /usr/share/fonts/truetype/dejavu/DejaVuSerifCondensed-Bold.ttf\n", + "Font N 29: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", + "Font N 30: /usr/share/fonts/truetype/fonts-yrsa-rasa/Yrsa-Medium.ttf\n", + "Font N 31: /usr/share/fonts/truetype/freefont/FreeSans.ttf\n", + "Font N 32: /usr/share/fonts/truetype/fonts-gujr-extra/padmaa-Bold.1.1.ttf\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_28967/2273520072.py:44: MatplotlibDeprecationWarning: \n", + "The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.\n", + " system_fonts = font_manager.get_fontconfig_fonts()\n", + "/tmp/ipykernel_28967/2273520072.py:59: DeprecationWarning: getsize is deprecated and will be removed in Pillow 10 (2023-07-01). Use getbbox or getlength instead.\n", + " posicion_texto = ((imagen.width - fuente.getsize(texto_linea)[0]) // 2,\n" + ] + } + ], + "source": [ + "# initializing size of string\n", + "N_total = 30000\n", + "img_shape = (1600,900)\n", + "N_lines = N_total//img_shape[1]\n", + "tamano_letra = 22\n", + "N_horizontal = img_shape[0]//(10*tamano_letra)\n", + "\n", + "print(N_lines)\n", + "print(N_horizontal)\n", + "\n", + "# Generating random strings\n", + "texto = ''.join(random.choices(string.ascii_letters +\n", + " string.digits, k=N_total))\n", + "\n", + "color_texto = \"black\"\n", + "fondo_color = \"white\"\n", + "ruta_guardado = \"./imagen_con_palabras.png\"\n", + "\n", + "# Random font por cada lĂ­nea\n", + "generar_imagen_con_palabras_rndfont(texto, img_shape, tamano_letra, color_texto, fondo_color, ruta_guardado)\n", + "\n", + "# Texto especificando un ttf\n", + "# tipo_letra = \"Playfair_Display/static/PlayfairDisplay-Black.ttf\" # Reemplaza con la ruta de tu tipo de letra\n", + "# generar_imagen_con_palabras(texto, img_shape, tipo_letra, tamano_letra, color_texto, fondo_color, ruta_guardado)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.9.13" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} From d1d5ba72ced58c9fb80c132c66c3564dc9c5a8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 17:01:05 -0300 Subject: [PATCH 2/9] Fix system fonts search --- text_generation/example.ipynb | 61 +++++------------------------------ 1 file changed, 8 insertions(+), 53 deletions(-) diff --git a/text_generation/example.ipynb b/text_generation/example.ipynb index 6729dc9..2a3be2c 100644 --- a/text_generation/example.ipynb +++ b/text_generation/example.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -22,7 +22,7 @@ " N_horizontal = img_shape[0]//(tamano_letra)\n", "\n", " # Get system font types\n", - " system_fonts = font_manager.get_fontconfig_fonts()\n", + " system_fonts = font_manager.findSystemFonts()\n", " # Filter out some non-readable fonts\n", " ttf_fonts = [font for font in system_fonts if ((\".ttf\" in font) and (\"lohit\" not in font) and (\"kacst\" not in font)) and (\"Navilu\" not in font) and (\"telu\" not in font) and (\"lyx\" not in font) and (\"malayalam\" not in font) and (\"tlwg\" not in font) and (\"samyak\" not in font) and (\"droid\" not in font) and (\"kalapi\" not in font) and (\"openoffice\" not in font) and (\"orya\" not in font)]\n", "\n", @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 210, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -60,26 +60,17 @@ "text": [ "147\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_28967/2165524556.py:1: MatplotlibDeprecationWarning: \n", - "The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.\n", - " system_fonts = font_manager.get_fontconfig_fonts()#findSystemFonts(fontpaths=None, fontext='ttf')\n" - ] } ], "source": [ - "system_fonts = font_manager.get_fontconfig_fonts()#findSystemFonts(fontpaths=None, fontext='ttf')\n", + "system_fonts = font_manager.findSystemFonts(fontpaths=None, fontext='ttf')\n", "ttf_fonts = [font for font in system_fonts if ((\".ttf\" in font) and (\"lohit\" not in font) and (\"kacst\" not in font)) and (\"Navilu\" not in font) and (\"telu\" not in font) and (\"lyx\" not in font) and (\"malayalam\" not in font) and (\"tlwg\" not in font) and (\"samyak\" not in font) and (\"droid\" not in font) and (\"kalapi\" not in font) and (\"openoffice\" not in font) and (\"orya\" not in font)]\n", "print(len(ttf_fonts))" ] }, { "cell_type": "code", - "execution_count": 209, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -87,50 +78,14 @@ "output_type": "stream", "text": [ "33\n", - "7\n", - "Font N 0: /usr/share/fonts/truetype/liberation2/LiberationSans-BoldItalic.ttf\n", - "Font N 1: /usr/share/fonts/truetype/liberation/LiberationSans-Italic.ttf\n", - "Font N 2: /usr/share/fonts/truetype/ubuntu/Ubuntu-C.ttf\n", - "Font N 3: /usr/share/fonts/truetype/ttf-bitstream-vera/VeraBI.ttf\n", - "Font N 4: /usr/share/fonts/truetype/ubuntu/UbuntuMono-R.ttf\n", - "Font N 5: /usr/share/fonts/truetype/lato/Lato-LightItalic.ttf\n", - "Font N 6: /usr/share/fonts/truetype/liberation2/LiberationSans-BoldItalic.ttf\n", - "Font N 7: /usr/share/fonts/truetype/liberation2/LiberationSans-Bold.ttf\n", - "Font N 8: /usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf\n", - "Font N 9: /usr/share/fonts/truetype/fonts-gujr-extra/Rekha.ttf\n", - "Font N 10: /usr/share/fonts/truetype/fonts-beng-extra/MuktiNarrowBold.ttf\n", - "Font N 11: /usr/share/fonts/truetype/tibetan-machine/TibetanMachineUni.ttf\n", - "Font N 12: /usr/share/fonts/truetype/Sahadeva/sahadeva.ttf\n", - "Font N 13: /usr/share/fonts/truetype/lato/Lato-Heavy.ttf\n", - "Font N 14: /usr/share/fonts/truetype/padauk/PadaukBook-Bold.ttf\n", - "Font N 15: /usr/share/fonts/truetype/padauk/Padauk-Bold.ttf\n", - "Font N 16: /usr/share/fonts/truetype/lato/Lato-Regular.ttf\n", - "Font N 17: /usr/share/fonts/truetype/pagul/Pagul.ttf\n", - "Font N 18: /usr/share/fonts/truetype/fonts-yrsa-rasa/Yrsa-SemiBold.ttf\n", - "Font N 19: /usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf\n", - "Font N 20: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", - "Font N 21: /usr/share/fonts/truetype/fonts-beng-extra/JamrulNormal.ttf\n", - "Font N 22: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", - "Font N 23: /usr/share/fonts/truetype/lato/Lato-Italic.ttf\n", - "Font N 24: /usr/share/fonts/truetype/liberation2/LiberationSerif-Regular.ttf\n", - "Font N 25: /usr/share/fonts/truetype/ubuntu/Ubuntu-L.ttf\n", - "Font N 26: /usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf\n", - "Font N 27: /usr/share/fonts/truetype/dejavu/DejaVuSerifCondensed-Bold.ttf\n", - "Font N 28: /usr/share/fonts/truetype/dejavu/DejaVuSerifCondensed-Bold.ttf\n", - "Font N 29: /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf\n", - "Font N 30: /usr/share/fonts/truetype/fonts-yrsa-rasa/Yrsa-Medium.ttf\n", - "Font N 31: /usr/share/fonts/truetype/freefont/FreeSans.ttf\n", - "Font N 32: /usr/share/fonts/truetype/fonts-gujr-extra/padmaa-Bold.1.1.ttf\n" + "7\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "/tmp/ipykernel_28967/2273520072.py:44: MatplotlibDeprecationWarning: \n", - "The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.\n", - " system_fonts = font_manager.get_fontconfig_fonts()\n", - "/tmp/ipykernel_28967/2273520072.py:59: DeprecationWarning: getsize is deprecated and will be removed in Pillow 10 (2023-07-01). Use getbbox or getlength instead.\n", + "/tmp/ipykernel_34832/450411713.py:33: DeprecationWarning: getsize is deprecated and will be removed in Pillow 10 (2023-07-01). Use getbbox or getlength instead.\n", " posicion_texto = ((imagen.width - fuente.getsize(texto_linea)[0]) // 2,\n" ] } @@ -186,7 +141,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.11.5" }, "orig_nbformat": 4 }, From cb1568be8a6bf33509437099a927b0507203a777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 18:21:49 -0300 Subject: [PATCH 3/9] WIP: add generation script. Always breaks with "OSError: invalid pixel size" --- text_generation/generate_random_text.py | 42 +++++++++++++++++++++++++ text_generation/text_utils.py | 42 +++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 text_generation/generate_random_text.py create mode 100644 text_generation/text_utils.py diff --git a/text_generation/generate_random_text.py b/text_generation/generate_random_text.py new file mode 100644 index 0000000..5eab22b --- /dev/null +++ b/text_generation/generate_random_text.py @@ -0,0 +1,42 @@ +import os +from datetime import date +import random +import string +from text_utils import generate_random_txt_img + +NUM_IMAGES = 10 +NUM_CHARACTERS = 25000 +IMG_SHAPE = (1600,900) +TEXT_SIZE = 22 + +today = date.today() + +# Month abbreviation, day and year +save_path = today.strftime("%b-%d-%Y") + +if not os.path.exists(save_path): + os.mkdir(save_path) +else: + i = 2 + save_path_tmp = save_path + str(i) + while os.path.exists(save_path_tmp): + i+=1 + save_path_tmp = save_path + str(i) + +images_name = "generated_text" + +for i in range(NUM_IMAGES): + + text = ''.join(random.choices(string.ascii_letters + + string.digits, k=NUM_CHARACTERS)) + + text_color = random.choices(["black","white"], weights=(70, 30), k=1)[0] + background_color = random.choices(["black","white"], weights=(30, 70), k=1)[0] + + generate_random_txt_img(text, + IMG_SHAPE, + TEXT_SIZE, + text_color, + background_color, + os.path.join(save_path,images_name+str(i)+".png")) + diff --git a/text_generation/text_utils.py b/text_generation/text_utils.py new file mode 100644 index 0000000..850cf92 --- /dev/null +++ b/text_generation/text_utils.py @@ -0,0 +1,42 @@ +from PIL import Image, ImageDraw, ImageFont +import random +import string +from matplotlib import font_manager + +def generate_random_txt_img(text, img_shape, text_size, text_color, background_color, save_path): + # Create white plain image + imagen = Image.new("RGB", img_shape, background_color) + dibujo = ImageDraw.Draw(imagen) + + # Compute amount of lines depending on image shape and number of characters + N_total = len(text) + N_lines = N_total//img_shape[1] + N_horizontal = img_shape[0]//(text_size) + + # Get system font types + system_fonts = font_manager.findSystemFonts() + # Filter out some non-readable fonts + ttf_fonts = [font for font in system_fonts if ((".ttf" in font) and ("lohit" not in font) and ("kacst" not in font)) and ("Navilu" not in font) and ("telu" not in font) and ("lyx" not in font) and ("malayalam" not in font) and ("tlwg" not in font) and ("samyak" not in font) and ("droid" not in font) and ("kalapi" not in font) and ("openoffice" not in font) and ("orya" not in font)] + + # Write over image one font per line + for iter in range(N_lines): + rnd_font_index = random.randint(0,len(ttf_fonts)-1) + random_font = ttf_fonts[rnd_font_index] + # print(f"Font N {iter}: {random_font}") + + # Load text font and set size + fuente = ImageFont.truetype(font=random_font, size=text_size) + # Get line text + texto_linea = text[iter * N_horizontal : (iter+1) * N_horizontal] + + # Adjust text position + posicion_texto = ((imagen.width - fuente.getsize(texto_linea)[0]) // 2, + int(1.5* iter * text_size) + ) + + # Write text + dibujo.text(posicion_texto, texto_linea, font=fuente, fill=text_color) + + # Save image + imagen.save(save_path) + From 79bda1f6392ae64a414b89de92d43f03d86827cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 22:40:48 -0300 Subject: [PATCH 4/9] Fix: white text when black background and vice versa --- text_generation/text_utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/text_generation/text_utils.py b/text_generation/text_utils.py index 850cf92..b6e6549 100644 --- a/text_generation/text_utils.py +++ b/text_generation/text_utils.py @@ -25,7 +25,12 @@ def generate_random_txt_img(text, img_shape, text_size, text_color, background_c # print(f"Font N {iter}: {random_font}") # Load text font and set size - fuente = ImageFont.truetype(font=random_font, size=text_size) + try: + fuente = ImageFont.truetype(font=random_font, size=text_size) + except: + # Load a fixed font when crashes + fuente = ImageFont.truetype("/usr/share/fonts/truetype/liberation2/LiberationSans-BoldItalic.ttf", size=text_size) + # Get line text texto_linea = text[iter * N_horizontal : (iter+1) * N_horizontal] From d614022b59622fb383bdcff74f894a8a743720e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 22:59:57 -0300 Subject: [PATCH 5/9] Manage error with fixed font --- text_generation/generate_random_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text_generation/generate_random_text.py b/text_generation/generate_random_text.py index 5eab22b..bd5b303 100644 --- a/text_generation/generate_random_text.py +++ b/text_generation/generate_random_text.py @@ -31,7 +31,7 @@ for i in range(NUM_IMAGES): string.digits, k=NUM_CHARACTERS)) text_color = random.choices(["black","white"], weights=(70, 30), k=1)[0] - background_color = random.choices(["black","white"], weights=(30, 70), k=1)[0] + background_color = "black"*(text_color=="white") + "white"*(text_color=="black") generate_random_txt_img(text, IMG_SHAPE, From b1d45543dc7a4619365a2cf417dd37b7f838e8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Mart=C3=ADnez?= Date: Tue, 26 Dec 2023 23:15:42 -0300 Subject: [PATCH 6/9] Change params for more text --- text_generation/generate_random_text.py | 2 +- text_generation/text_utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/text_generation/generate_random_text.py b/text_generation/generate_random_text.py index bd5b303..8de14cd 100644 --- a/text_generation/generate_random_text.py +++ b/text_generation/generate_random_text.py @@ -5,7 +5,7 @@ import string from text_utils import generate_random_txt_img NUM_IMAGES = 10 -NUM_CHARACTERS = 25000 +NUM_CHARACTERS = 29000 IMG_SHAPE = (1600,900) TEXT_SIZE = 22 diff --git a/text_generation/text_utils.py b/text_generation/text_utils.py index b6e6549..5adf382 100644 --- a/text_generation/text_utils.py +++ b/text_generation/text_utils.py @@ -11,7 +11,7 @@ def generate_random_txt_img(text, img_shape, text_size, text_color, background_c # Compute amount of lines depending on image shape and number of characters N_total = len(text) N_lines = N_total//img_shape[1] - N_horizontal = img_shape[0]//(text_size) + N_horizontal = int(1.6 * img_shape[0] // (text_size)) # Get system font types system_fonts = font_manager.findSystemFonts() @@ -36,7 +36,7 @@ def generate_random_txt_img(text, img_shape, text_size, text_color, background_c # Adjust text position posicion_texto = ((imagen.width - fuente.getsize(texto_linea)[0]) // 2, - int(1.5* iter * text_size) + int(1.25* iter * text_size) ) # Write text From e50d1a56554a7ccee2ada0383909dadbd0090b8f Mon Sep 17 00:00:00 2001 From: Emilio Martinez Date: Thu, 11 Jan 2024 11:42:32 -0300 Subject: [PATCH 7/9] Add delayed differential signaling to simulation --- end-to-end/folder_simulation.py | 30 ++++++++++++++++++---- end-to-end/options/tempest_simulation.json | 12 ++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/end-to-end/folder_simulation.py b/end-to-end/folder_simulation.py index 76b9fcd..a4de145 100644 --- a/end-to-end/folder_simulation.py +++ b/end-to-end/folder_simulation.py @@ -46,21 +46,30 @@ def image_transmition_simulation(I, blanking=False): return I_TMDS_Tx, I_TMDS.shape def image_capture_simulation(I_Tx, h_total, v_total, N_harmonic, sdr_rate = 50e6, - noise_std=0, fps=60, freq_error=0, phase_error=0): + noise_std=0, fps=60, freq_error=0, phase_error=0, + interpolator=None, diff_signaling=False): # Compute pixelrate and bitrate px_rate = h_total*v_total*fps bit_rate = 10*px_rate # Continuous samples (interpolate) - interpolator = int(np.ceil(N_harmonic/5)) # Condition for sampling rate and - sample_rate = interpolator*bit_rate - Nsamples = interpolator*(10*h_total*v_total) + if interpolator: + sample_rate = interpolator*bit_rate + else: + interpolator = int(np.ceil(N_harmonic/5)) # Condition for sampling rate + if interpolator > 1: I_Tx_continuous = np.repeat(I_Tx,interpolator) else: I_Tx_continuous = I_Tx + + # Differential signaling + if (diff_signaling) and (interpolator != 1): + I_Tx_continuous = np.diff(I_Tx_continuous) + Nsamples = len(I_Tx_continuous) + # Add Gaussian noise if noise_std > 0: noise_sigma = noise_std/15.968719423 # sqrt(255)~15.968719423 @@ -142,6 +151,8 @@ def main(simulation_options_path = 'options/tempest_simulation.json'): blanking = options['options']['blanking'] fps = options['options']['frames_per_second'] sdr_rate = options['options']['sdr_rate'] + interpolator = options['options']['interpolator'] + differential_signaling = options['options']['differential_signaling'] harmonics = options['options']['random']['harmonics'] freq_error_range = options['options']['random']['freq_error'] phase_error_range = options['options']['random']['phase_error'] @@ -155,11 +166,19 @@ def main(simulation_options_path = 'options/tempest_simulation.json'): # Get images and subfolders names images = get_images_names_from_folder(input_folder) + + # Get images names from output folder + output_existing_images = get_images_names_from_folder(output_folder) # Initialize processing time t_all_images = 0 for image in images: + + # Check if image already simulated + if image in output_existing_images: + output_existing_images.remove(image) + continue # timestamp for simulation starting t1_image = time.time() @@ -184,7 +203,8 @@ def main(simulation_options_path = 'options/tempest_simulation.json'): v_res, h_res, _ = resolution I_capture = image_capture_simulation(I_Tx, h_res, v_res, N_harmonic, sdr_rate, - sigma, fps, freq_error, phase_error) + sigma, fps, freq_error, phase_error, + interpolator, differential_signaling) path = os.path.join(output_folder,image) diff --git a/end-to-end/options/tempest_simulation.json b/end-to-end/options/tempest_simulation.json index f7e1939..34b1efc 100644 --- a/end-to-end/options/tempest_simulation.json +++ b/end-to-end/options/tempest_simulation.json @@ -1,9 +1,9 @@ { "paths": { - "folder_original_images": "path/to/folder", + "folder_original_images": "/home/ceibal-anii/emilio/pfc/deep-tempest/end-to-end/sinteticas/trainsets/ground-truth", "__comment1__": "Insert input folder (original images)", - "folder_simulated_images": "path/to/new_folder", + "folder_simulated_images": "/home/ceibal-anii/emilio/pfc/deep-tempest/end-to-end/imgs_diff_signaling/trainsets", "__comment2__": "Insert output folder (tempest degraded images)" }, @@ -17,6 +17,12 @@ "sdr_rate": 50e6, "__comment3__": "sampling rate of SDR", + "interpolator": 10, + "__comment4__": "Interpolation for analog pulse simulation", + + "differential_signaling": true, + "__comment5__": "Use diferential signaling. Epsilon delay as one interpolation unit", + "random": { "harmonics": [3], @@ -25,7 +31,7 @@ "sigma": null, "__comment2__":"Gaussian noise with random sigma over specified range [sigma1, simga2]", - "freq_error": [0,50], + "freq_error": [0,15], "__comment3__": "Random frequency error (Hz) over specified range [f1, f2]", "phase_error": [-1,1], From 0715eda4f6a3a946f5ececfa6b1586b40beae6dc Mon Sep 17 00:00:00 2001 From: Emilio Martinez Date: Tue, 23 Jan 2024 14:24:56 -0300 Subject: [PATCH 8/9] Ignore logs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9d40cb2..3335bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ gr-tempest/examples/simulations/*.py scripts/__pycache__ scripts/*.jpg scripts/*.png +*.log From 18475ea8eb6d670c6eae6f27713404a133a67d20 Mon Sep 17 00:00:00 2001 From: Emilio Martinez Date: Tue, 23 Jan 2024 14:26:09 -0300 Subject: [PATCH 9/9] Compute metrics when testing --- .../data/dataset_deeptempest_finetuning.py | 2 +- end-to-end/main_test_drunet.py | 77 ++++++++++++++----- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/end-to-end/data/dataset_deeptempest_finetuning.py b/end-to-end/data/dataset_deeptempest_finetuning.py index 2203710..afea870 100644 --- a/end-to-end/data/dataset_deeptempest_finetuning.py +++ b/end-to-end/data/dataset_deeptempest_finetuning.py @@ -41,7 +41,7 @@ class DatasetDrunetFineTune(data.Dataset): contains one or more L representations of the H image. """ - assert os.path.isdir(opt['dataroot_H']), "No es dir" + assert os.path.isdir(opt['dataroot_H']), f"{opt['dataroot_H']} is not a directory" self.paths_H = [f for f in os.listdir(opt['dataroot_H']) if os.path.isfile(os.path.join(opt['dataroot_H'],f))] #------------------------------------------------------------------------------------------------------ # For the above step you can use util.get_image_paths(), but it goes recursevely throught the tree dirs diff --git a/end-to-end/main_test_drunet.py b/end-to-end/main_test_drunet.py index f7a62b5..b651b26 100644 --- a/end-to-end/main_test_drunet.py +++ b/end-to-end/main_test_drunet.py @@ -18,6 +18,27 @@ from utils.utils_dist import get_dist_info, init_dist from data.select_dataset import define_Dataset from models.select_model import define_Model +# OCR metrics +# First, must install Tesseract: https://tesseract-ocr.github.io/tessdoc/Installation.html +# Second, install CER/WER and tesseract python wrapper libraries +# pip install fastwer +# pip install pybind11 +# pip install pytesseract +import pytesseract +import fastwer + + +def calculate_cer_wer(img_E, img_H): + # Transcribe ground-truth image to text + text_H = pytesseract.image_to_string(img_H).strip().replace('\n',' ') + + # Transcribe estimated image to text + text_E = pytesseract.image_to_string(img_E).strip().replace('\n',' ') + + cer = fastwer.score_sent(text_E, text_H, char_level=True) + wer = fastwer.score_sent(text_E, text_H) + + return cer, wer ''' # -------------------------------------------- @@ -96,6 +117,7 @@ def main(json_path='options/test_drunet.json'): # ---------------------------------------- """ L_paths = util.get_image_paths(opt['datasets']['test']['dataroot_L']) + H_paths = util.get_image_paths(opt['datasets']['test']['dataroot_H']) noise_sigma = opt['datasets']['test']['sigma_test'] ''' @@ -103,12 +125,15 @@ def main(json_path='options/test_drunet.json'): # Step--4 (main test) # ---------------------------------------- ''' - # avg_psnr = 0.0 - # avg_ssim = 0.0 - # idx = 0 + avg_psnr = 0.0 + avg_ssim = 0.0 + avg_edgeJaccard = 0.0 + avg_cer = 0.0 + avg_wer = 0.0 + idx = 0 - for L_path in L_paths: - # idx += 1 + for L_path, H_path in zip(L_paths,H_paths): + idx += 1 image_name_ext = os.path.basename(L_path) img_name, ext = os.path.splitext(image_name_ext) @@ -118,7 +143,7 @@ def main(json_path='options/test_drunet.json'): logger.info('Creating inference on test image...') # Load image - img_L_original = util.imread_uint(L_path, n_channels=3) + img_L_original = util.imread_uint(L_path, n_channels=3)[50:-50,100:-100,:] img_L = img_L_original[:,:,:2] img_L = util.uint2single(img_L) img_L = util.single2tensor4(img_L) @@ -150,26 +175,36 @@ def main(json_path='options/test_drunet.json'): logger.info(f'Inference of {img_name} completed. Saved at {img_dir}.') - # ----------------------- - # calculate PSNR - # ----------------------- - # current_psnr = util.calculate_psnr(E_img, H_img) + # Load H image and compute metrics + img_H = util.imread_uint(H_path, n_channels=3) + if img_H.ndim == 3: + img_H = np.mean(img_H, axis=2) + img_H = img_H.astype('uint8') - # ----------------------- - # calculate SSIM - # ----------------------- - # current_ssim = util.calculate_ssim(E_img, H_img) + # ---------------------------------------- + # compute PSNR, SSIM, edgeJaccard and CER + # ---------------------------------------- + current_psnr = util.calculate_psnr(img_E, img_H) + current_ssim = util.calculate_ssim(img_E, img_H) + current_edgeJaccard = util.calculate_edge_jaccard(img_E, img_H) + current_cer, current_wer = calculate_cer_wer(img_E, img_H) - # logger.info('{:->4d}--> {:>10s} | PSNR = {:<4.2f}dB, SSIM = {:<4.2f}'.format(idx, image_name_ext, current_psnr, current_ssim)) + logger.info('{:->4d}--> {:>10s} | PSNR = {:<4.2f}dB ; SSIM = {:.3f} ; edgeJaccard = {:.3f} ; CER = {:.3f}% ; WER = {:.3f}%'.format(idx, image_name_ext, current_psnr, current_ssim, current_edgeJaccard, current_cer, current_wer)) - # avg_psnr += current_psnr - # avg_ssim += current_ssim + avg_psnr += current_psnr + avg_ssim += current_ssim + avg_edgeJaccard += current_edgeJaccard + avg_cer += current_cer + avg_wer += current_wer - # avg_psnr = avg_psnr / idx - # avg_ssim = avg_ssim / idx + avg_psnr = avg_psnr / idx + avg_ssim = avg_ssim / idx + avg_edgeJaccard = avg_edgeJaccard / idx + avg_cer = avg_cer / idx + avg_wer = avg_wer / idx - # testing log - # logger.info('Average PSNR : {:<.2f}dB, Average SSIM : {:<4.2f}\n'.format(avg_psnr, avg_ssim)) + # Average log + logger.info('[Average metrics] PSNR : {:<4.2f}dB, SSIM = {:.3f} : edgeJaccard = {:.3f} : CER = {:.3f}% : WER = {:.3f}%'.format(avg_psnr, avg_ssim, avg_edgeJaccard, avg_cer, avg_wer)) if __name__ == '__main__': main()