{
  "id": 582286,
  "title": "18th Place Solution - Homemade Vectorizer + ImageReward + NLTK",
  "content": "<p>This is my first Kaggle competition. In my spare time, I work on a side project developing algorithms and tools for creating vector art. Therefore, I am thrilled to have found this competition, which gives me the opportunity to test my algorithms and explore the new possibilities brought by machine learning. I have learnt a lot from public codes and discussions. Thank you to the organizers for hosting the event and to all the participants for sharing so many wonderful ideas.</p>\n<p>My approach is based on the following paper:</p>\n<blockquote>\n  <p>Karthik, Shyamgopal, Karsten Roth, Massimiliano Mancini, and Zeynep Akata. \"If at First You Don't Succeed, Try, Try Again: Faithful Diffusion-based Text-to-Image Generation by Selection.\" arXiv preprint arXiv:2305.13308 (2023).</p>\n</blockquote>\n<p>This work claims that ranking generated images with <a href=\"https://github.com/THUDM/ImageReward\" target=\"_blank\">ImageReward</a> will increase the TIFA score. The overview of my pipeline is:</p>\n<ol>\n<li>Generate several images using Flux.1 Schnell</li>\n<li>Vectorize the images using my own method</li>\n<li>Calculate the ImageReward metric and the aesthetic score of each image</li>\n<li>Pick the image with the highest score and do final adjustments (e.g. changing vectorization parameters, adding a letter for OCR)</li>\n</ol>\n<p>During step 1 and 3, I also use <a href=\"https://www.nltk.org/\" target=\"_blank\">NLTK</a> to alter the original prompt.</p>\n<h2>Raster Image Generation</h2>\n<p>I deployed a quantized Flux.1 Schnell with the following prompt: <code>{image_description}, stylized proportions, exaggerated form, children illustration</code>. For quantization, I tried both Q4 and nf4. Q4 behaves slightly better.</p>\n<h2>Vectorization</h2>\n<p>I took codes from my <a href=\"https://github.com/chsh2/nijiGPen/blob/main/operators/operator_io_raster.py\" target=\"_blank\">another project</a> for image vectorization. It may not be as good as VTracer in general, but I tried to focus on generating clean geometry without unnecessary structures. Therefore, I think it may fit here.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fd21845b78c20c66aa9e6598908e6a086%2F1.png?generation=1748595516333186&amp;alt=media\" alt=\"\"></p>\n<p>The method is based on a common approach that first performs color quantization and then extracts the contours as polygon paths. While I tried to make some improvements in each step:</p>\n<ol>\n<li><strong>Color Quantization</strong>: To balance the efficiency and quality, I use a combination of K-means clustering and <a href=\"https://scikit-image.org/docs/0.25.x/api/skimage.segmentation.html#skimage.segmentation.felzenszwalb\" target=\"_blank\">Felsenszwalb algorithm</a>. I also convert the image from RGB to LAB space for better result.</li>\n<li><strong>Contour Finding</strong>: Both OpenCV and Skimage provide <code>find_contours</code> API for a binary bitmap, so it needs to be called multiple times for each color in the quantized image. But the underlying algorithm (marching squares) can actually be applied to a multi-color bitmap without changes. I reimplemented this algorithm so that it only needs to be run once during vectorization.</li>\n<li><strong>Path Simplification</strong>: During simplifying each polygon path, I keep points which have 3 colors in their neighborhood unchanged. Otherwise, gaps may appear between adjacent shapes. This improvement is less important, since gaps do not necessarily lead to low aesthetic scores. I cancel this constraint when a higher level of compression is needed. The method to simplify a path is the Douglas-Peucker algorithm.</li>\n</ol>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2F9f64f1df4569cf7bebd2afc128f0bf17%2F2.png?generation=1748595536980386&amp;alt=media\" alt=\"\"></p>\n<p>I prepared 4 sets of vectorization parameters that satisfies the SVG file size limit. Scores are estimated for each version of the converted image to determine the best one.</p>\n<h2>Prompt Processing &amp; Scoring</h2>\n<p>The paper I cited calculated the ImageReward metric using the original prompt. I discovered that dividing the prompt into several parts could result in a higher competition score. Using NLTK, I located all the nouns and created a sub-prompt for each one. Then, I used a concave function to get the average of the ImageReward metrics of all the sub-prompts.</p>\n<p>In my tests, ImageReward behaves better than Clip and SigLIP as an indicator of the competition score. I did not compare it with VQA approaches though.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fba0328078e2600e2285eaf50c79cd728%2F3.png?generation=1748595553318031&amp;alt=media\" alt=\"\"></p>\n<p>I also use NLTK for another purpose during image generation. I found that Flux.1 always failed to generate correct images of some abstract subjects such as trapezoids. I tried to alleviate this problem by attaching the word definition to the prompt. For example:</p>\n<pre><code>magenta trapezoids (a quadrilateral with two parallel sides) layered on a transluscent silver sheet (any broad thin expanse or surface)\n</code></pre>\n<p>This approach does not always make improvements. Therefore I generated multiple images for both versions of prompts for ImageReward to score.</p>\n<h2>Other Thoughts</h2>\n<p>I am very grateful to Kaggle for providing GPU resources that have enabled me to put various ideas into practice. At the same time, I am also impressed by the organizers' ongoing efforts to improve the scoring metrics to ensure the fairness of the competition. </p>\n<p>However, I have one regret that my initial goal of testing my vector algorithms was not fully achieved. Besides raster image vectorization, I have some other algorithms for vector art, but cannot find a place to use them in the competition, since the metrics are quite specific to raster images. The aesthetic score is trained on photos, and VQA is also less precise for vector images. On the other hand, there is no metric evaluating vector image features or the SVG format. It is not a surprise to me that most participants prefer diffusers to LLM, since it looks more like a competition to generate highly-compressed raster images instead of vector images.</p>\n<p>My takeaway from this is that we should perhaps be more aware of the limitations of this type of purely training-based metrics/scorers. This may be a bit off topic, but I do not like the fact that some people treat artists merely as training sources and downplay their expertise and judgements. On the one hand, as someone developing tools for artists, I am distressed to see the increasing conflicts between developers and artists. On the other hand, I also believe that respecting each other's knowledge is the key to make further progress.</p>",
  "comments": [],
  "comment_count": 0,
  "messages": [
    {
      "id": 3213618,
      "postDate": "2025-05-30T09:01:30.990Z",
      "content": "<p>This is my first Kaggle competition. In my spare time, I work on a side project developing algorithms and tools for creating vector art. Therefore, I am thrilled to have found this competition, which gives me the opportunity to test my algorithms and explore the new possibilities brought by machine learning. I have learnt a lot from public codes and discussions. Thank you to the organizers for hosting the event and to all the participants for sharing so many wonderful ideas.</p>\n<p>My approach is based on the following paper:</p>\n<blockquote>\n  <p>Karthik, Shyamgopal, Karsten Roth, Massimiliano Mancini, and Zeynep Akata. \"If at First You Don't Succeed, Try, Try Again: Faithful Diffusion-based Text-to-Image Generation by Selection.\" arXiv preprint arXiv:2305.13308 (2023).</p>\n</blockquote>\n<p>This work claims that ranking generated images with <a href=\"https://github.com/THUDM/ImageReward\" target=\"_blank\">ImageReward</a> will increase the TIFA score. The overview of my pipeline is:</p>\n<ol>\n<li>Generate several images using Flux.1 Schnell</li>\n<li>Vectorize the images using my own method</li>\n<li>Calculate the ImageReward metric and the aesthetic score of each image</li>\n<li>Pick the image with the highest score and do final adjustments (e.g. changing vectorization parameters, adding a letter for OCR)</li>\n</ol>\n<p>During step 1 and 3, I also use <a href=\"https://www.nltk.org/\" target=\"_blank\">NLTK</a> to alter the original prompt.</p>\n<h2>Raster Image Generation</h2>\n<p>I deployed a quantized Flux.1 Schnell with the following prompt: <code>{image_description}, stylized proportions, exaggerated form, children illustration</code>. For quantization, I tried both Q4 and nf4. Q4 behaves slightly better.</p>\n<h2>Vectorization</h2>\n<p>I took codes from my <a href=\"https://github.com/chsh2/nijiGPen/blob/main/operators/operator_io_raster.py\" target=\"_blank\">another project</a> for image vectorization. It may not be as good as VTracer in general, but I tried to focus on generating clean geometry without unnecessary structures. Therefore, I think it may fit here.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fd21845b78c20c66aa9e6598908e6a086%2F1.png?generation=1748595516333186&amp;alt=media\" alt=\"\"></p>\n<p>The method is based on a common approach that first performs color quantization and then extracts the contours as polygon paths. While I tried to make some improvements in each step:</p>\n<ol>\n<li><strong>Color Quantization</strong>: To balance the efficiency and quality, I use a combination of K-means clustering and <a href=\"https://scikit-image.org/docs/0.25.x/api/skimage.segmentation.html#skimage.segmentation.felzenszwalb\" target=\"_blank\">Felsenszwalb algorithm</a>. I also convert the image from RGB to LAB space for better result.</li>\n<li><strong>Contour Finding</strong>: Both OpenCV and Skimage provide <code>find_contours</code> API for a binary bitmap, so it needs to be called multiple times for each color in the quantized image. But the underlying algorithm (marching squares) can actually be applied to a multi-color bitmap without changes. I reimplemented this algorithm so that it only needs to be run once during vectorization.</li>\n<li><strong>Path Simplification</strong>: During simplifying each polygon path, I keep points which have 3 colors in their neighborhood unchanged. Otherwise, gaps may appear between adjacent shapes. This improvement is less important, since gaps do not necessarily lead to low aesthetic scores. I cancel this constraint when a higher level of compression is needed. The method to simplify a path is the Douglas-Peucker algorithm.</li>\n</ol>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2F9f64f1df4569cf7bebd2afc128f0bf17%2F2.png?generation=1748595536980386&amp;alt=media\" alt=\"\"></p>\n<p>I prepared 4 sets of vectorization parameters that satisfies the SVG file size limit. Scores are estimated for each version of the converted image to determine the best one.</p>\n<h2>Prompt Processing &amp; Scoring</h2>\n<p>The paper I cited calculated the ImageReward metric using the original prompt. I discovered that dividing the prompt into several parts could result in a higher competition score. Using NLTK, I located all the nouns and created a sub-prompt for each one. Then, I used a concave function to get the average of the ImageReward metrics of all the sub-prompts.</p>\n<p>In my tests, ImageReward behaves better than Clip and SigLIP as an indicator of the competition score. I did not compare it with VQA approaches though.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fba0328078e2600e2285eaf50c79cd728%2F3.png?generation=1748595553318031&amp;alt=media\" alt=\"\"></p>\n<p>I also use NLTK for another purpose during image generation. I found that Flux.1 always failed to generate correct images of some abstract subjects such as trapezoids. I tried to alleviate this problem by attaching the word definition to the prompt. For example:</p>\n<pre><code>magenta trapezoids (a quadrilateral with two parallel sides) layered on a transluscent silver sheet (any broad thin expanse or surface)\n</code></pre>\n<p>This approach does not always make improvements. Therefore I generated multiple images for both versions of prompts for ImageReward to score.</p>\n<h2>Other Thoughts</h2>\n<p>I am very grateful to Kaggle for providing GPU resources that have enabled me to put various ideas into practice. At the same time, I am also impressed by the organizers' ongoing efforts to improve the scoring metrics to ensure the fairness of the competition. </p>\n<p>However, I have one regret that my initial goal of testing my vector algorithms was not fully achieved. Besides raster image vectorization, I have some other algorithms for vector art, but cannot find a place to use them in the competition, since the metrics are quite specific to raster images. The aesthetic score is trained on photos, and VQA is also less precise for vector images. On the other hand, there is no metric evaluating vector image features or the SVG format. It is not a surprise to me that most participants prefer diffusers to LLM, since it looks more like a competition to generate highly-compressed raster images instead of vector images.</p>\n<p>My takeaway from this is that we should perhaps be more aware of the limitations of this type of purely training-based metrics/scorers. This may be a bit off topic, but I do not like the fact that some people treat artists merely as training sources and downplay their expertise and judgements. On the one hand, as someone developing tools for artists, I am distressed to see the increasing conflicts between developers and artists. On the other hand, I also believe that respecting each other's knowledge is the key to make further progress.</p>",
      "rawMarkdown": "This is my first Kaggle competition. In my spare time, I work on a side project developing algorithms and tools for creating vector art. Therefore, I am thrilled to have found this competition, which gives me the opportunity to test my algorithms and explore the new possibilities brought by machine learning. I have learnt a lot from public codes and discussions. Thank you to the organizers for hosting the event and to all the participants for sharing so many wonderful ideas.\n\nMy approach is based on the following paper:\n\n> Karthik, Shyamgopal, Karsten Roth, Massimiliano Mancini, and Zeynep Akata. \"If at First You Don't Succeed, Try, Try Again: Faithful Diffusion-based Text-to-Image Generation by Selection.\" arXiv preprint arXiv:2305.13308 (2023).\n\nThis work claims that ranking generated images with [ImageReward](https://github.com/THUDM/ImageReward) will increase the TIFA score. The overview of my pipeline is:\n\n1. Generate several images using Flux.1 Schnell\n2. Vectorize the images using my own method\n3. Calculate the ImageReward metric and the aesthetic score of each image\n4. Pick the image with the highest score and do final adjustments (e.g. changing vectorization parameters, adding a letter for OCR)\n\nDuring step 1 and 3, I also use [NLTK](https://www.nltk.org/) to alter the original prompt.\n\n## Raster Image Generation\n\nI deployed a quantized Flux.1 Schnell with the following prompt: `{image_description}, stylized proportions, exaggerated form, children illustration`. For quantization, I tried both Q4 and nf4. Q4 behaves slightly better.\n\n## Vectorization\n\nI took codes from my [another project](https://github.com/chsh2/nijiGPen/blob/main/operators/operator_io_raster.py) for image vectorization. It may not be as good as VTracer in general, but I tried to focus on generating clean geometry without unnecessary structures. Therefore, I think it may fit here.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fd21845b78c20c66aa9e6598908e6a086%2F1.png?generation=1748595516333186&alt=media)\n\nThe method is based on a common approach that first performs color quantization and then extracts the contours as polygon paths. While I tried to make some improvements in each step:\n\n1. **Color Quantization**: To balance the efficiency and quality, I use a combination of K-means clustering and [Felsenszwalb algorithm](https://scikit-image.org/docs/0.25.x/api/skimage.segmentation.html#skimage.segmentation.felzenszwalb). I also convert the image from RGB to LAB space for better result.\n2. **Contour Finding**: Both OpenCV and Skimage provide `find_contours` API for a binary bitmap, so it needs to be called multiple times for each color in the quantized image. But the underlying algorithm (marching squares) can actually be applied to a multi-color bitmap without changes. I reimplemented this algorithm so that it only needs to be run once during vectorization.\n3. **Path Simplification**: During simplifying each polygon path, I keep points which have 3 colors in their neighborhood unchanged. Otherwise, gaps may appear between adjacent shapes. This improvement is less important, since gaps do not necessarily lead to low aesthetic scores. I cancel this constraint when a higher level of compression is needed. The method to simplify a path is the Douglas-Peucker algorithm.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2F9f64f1df4569cf7bebd2afc128f0bf17%2F2.png?generation=1748595536980386&alt=media)\n\nI prepared 4 sets of vectorization parameters that satisfies the SVG file size limit. Scores are estimated for each version of the converted image to determine the best one.\n\n## Prompt Processing & Scoring\n\nThe paper I cited calculated the ImageReward metric using the original prompt. I discovered that dividing the prompt into several parts could result in a higher competition score. Using NLTK, I located all the nouns and created a sub-prompt for each one. Then, I used a concave function to get the average of the ImageReward metrics of all the sub-prompts.\n\nIn my tests, ImageReward behaves better than Clip and SigLIP as an indicator of the competition score. I did not compare it with VQA approaches though.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F6185948%2Fba0328078e2600e2285eaf50c79cd728%2F3.png?generation=1748595553318031&alt=media)\n\nI also use NLTK for another purpose during image generation. I found that Flux.1 always failed to generate correct images of some abstract subjects such as trapezoids. I tried to alleviate this problem by attaching the word definition to the prompt. For example:\n\n```plaintext\nmagenta trapezoids (a quadrilateral with two parallel sides) layered on a transluscent silver sheet (any broad thin expanse or surface)\n```\n\nThis approach does not always make improvements. Therefore I generated multiple images for both versions of prompts for ImageReward to score.\n\n## Other Thoughts\n\nI am very grateful to Kaggle for providing GPU resources that have enabled me to put various ideas into practice. At the same time, I am also impressed by the organizers' ongoing efforts to improve the scoring metrics to ensure the fairness of the competition. \n\nHowever, I have one regret that my initial goal of testing my vector algorithms was not fully achieved. Besides raster image vectorization, I have some other algorithms for vector art, but cannot find a place to use them in the competition, since the metrics are quite specific to raster images. The aesthetic score is trained on photos, and VQA is also less precise for vector images. On the other hand, there is no metric evaluating vector image features or the SVG format. It is not a surprise to me that most participants prefer diffusers to LLM, since it looks more like a competition to generate highly-compressed raster images instead of vector images.\n\nMy takeaway from this is that we should perhaps be more aware of the limitations of this type of purely training-based metrics/scorers. This may be a bit off topic, but I do not like the fact that some people treat artists merely as training sources and downplay their expertise and judgements. On the one hand, as someone developing tools for artists, I am distressed to see the increasing conflicts between developers and artists. On the other hand, I also believe that respecting each other's knowledge is the key to make further progress.\n",
      "votes": 6
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-20T09:11:13Z",
  "competition_id": 89659,
  "competition_slug": "drawing-with-llms",
  "team_id": 13664116,
  "solution_url": "/competitions/drawing-with-llms/writeups/chsh2-18th-place-solution-homemade-vectorizer-imag"
}