{"id":16321438,"url":"https://github.com/echo-lalia/hd-mosaic","last_synced_at":"2025-10-31T18:30:28.146Z","repository":{"id":255688285,"uuid":"853169719","full_name":"echo-lalia/hd-mosaic","owner":"echo-lalia","description":"A script that uses Pillow + Numpy to compare and assemble an image collage based on a given target image and source tiles.","archived":false,"fork":false,"pushed_at":"2024-09-15T23:37:07.000Z","size":14173,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-25T19:24:35.123Z","etag":null,"topics":["art","collage","image","mosaic","photo","photomosaic-generator","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/echo-lalia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-06T06:00:23.000Z","updated_at":"2024-09-15T23:35:54.000Z","dependencies_parsed_at":"2024-11-06T14:51:37.238Z","dependency_job_id":null,"html_url":"https://github.com/echo-lalia/hd-mosaic","commit_stats":null,"previous_names":["echo-lalia/imagecollage","echo-lalia/hd-mosaic"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echo-lalia%2Fhd-mosaic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echo-lalia%2Fhd-mosaic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echo-lalia%2Fhd-mosaic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/echo-lalia%2Fhd-mosaic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/echo-lalia","download_url":"https://codeload.github.com/echo-lalia/hd-mosaic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239221175,"owners_count":19602380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["art","collage","image","mosaic","photo","photomosaic-generator","python"],"created_at":"2024-10-10T22:47:48.429Z","updated_at":"2025-10-31T18:30:28.091Z","avatar_url":"https://github.com/echo-lalia.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HD Mosaic\n\nA script that creates a photo mosaic by comparing sub-tile pixels for a higher quality result.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"misc/images/cover.jpg\" alt=\"Cover Art\"/\u003e\n\u003c/p\u003e\n\nThis script works differently than most others because it doesn't just treat each image tile as one pixel, but instead compares the contents of the image (using a limited, configurable resolution), and finds the best match.\n\nThis, of course, is much slower than other methods like mapping tiles to pixels, or just overlaying the source image on the final image. However, the results look much nicer, too (at least, in my opinion).  \nIn order to speed up the process, imported image tiles are first converted into Numpy arrays, and fast np.array math is used to compare tiles and find the best matches.\n\n\u003cbr/\u003e\u003cbr/\u003e\n\n## How this differs from other methods of generating mosaics\n\n\u003e **Note:* The example images in this section are made using a low resolution to exaggerate the differences. People usually prefer to use a higher resolution.*  \n\u003e *The input arguments used to create each example mosaic are listed beneath them.*\n\nThere are a couple of different common methods for generating a mosaic image.  \n\n\u003cbr/\u003e\n\n### Simple overlay:\n\nThe first one, which is commonly used to make mosaics in Photoshop, as well as in many online tools, is to simply overlay the desired image on top of a series of random images.  \n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eTarget Image\u003c/th\u003e\n    \u003cth\u003e\u003c/th\u003e\n    \u003cth\u003eOverlay on random tiles\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\example_image.jpg\" height=300 \u003e \u003cbr/\u003e\u0026nbsp\n    \u003c/td\u003e\n    \u003ctd\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/td\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\mosaic_16x16_l0.0_k0.0_r1.0_O1.0_so0.0.jpg\" height=300\u003e \n      \u003cbr/\u003e\u003cbr/\u003e\u003csup\u003e\n\n`-l 0.0 -k 0.0 -r 1.0 -O 1.0 -so 0.0`\n\n\u003c/sup\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nThis is the way I first learned to make mosaics, but I'm not really a fan of it.  \nIf you use a really high resolution backdrop, the effect can be somewhat convincing. But, to me, the fact that the tiles have nothing to do with the overlaid image bothers me, and ruins the \"charm\" of the photo mosaic.  \n\nAnd, if you look closely, the effect is completely ruined, because you can see how the tiled images just have random lines and streaks of color going through them, which obviously weren't there in the original image.\n\n\u003cbr/\u003e\n\n\n### Tiles representing pixels:\n\nThe next strategy I usually see, is a method which involves pixelating the target image, mapping each image tile to an RGB value by averaging, and then selecting the image that has the closest color to each pixel.  \nI like this strategy a lot better than the overlay strategy, but it still requires a fairly high resolution image for the target image to become clear.\n\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eTarget Image\u003c/th\u003e\n    \u003cth\u003e\u003c/th\u003e\n    \u003cth\u003eTiles mapped to RGB values\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\example_image.jpg\" height=300 \u003e \u003cbr/\u003e\u0026nbsp\n    \u003c/td\u003e\n    \u003ctd\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/td\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\mosaic_16x16_c0.015_k0.0_r0.0_O0.0_so0.0.jpg\" height=300\u003e \n      \u003cbr/\u003e\u003cbr/\u003e\u003csup\u003e\n\n`-c 0.015 -k 0.0 -r 0.0 -O 0.0 -so 0.0`\n\n\u003c/sup\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nIf you really squint/blur your eyes, you can still kinda see the target image in the result.  \nBut, to get good results you really need a high number of tiles. In my opinion, using a high number of tiles can harm the effect, because it makes it much more difficult to make out the images in each individual tile.\n\n\u003cbr/\u003e\n\n\n\n\n## How these mosaics are generated:\n\nThis script can do both of the above methods for generating its mosaics, but there are some really important additions and changes in the implementation.\n\n\u003cbr/\u003e\n\n\n\n### Comparing pixels within the tiles:\nRather than mapping each tile to a single RGB value, the input tiles are scaled down to a configurable resolution, and compared pixel-to-pixel with the target image, in order to find the best match.\n\nThis is really important because it means that tiles aren't just chosen based on one overall color, but also their overall *shape*\n\n\u003e *The comparison is done in LAB color space, and two comparisons are actually done:*  \n\u003e - *The LAB pixel values are directly compared between the tiles*  \n\u003e - *The average difference of each pixel from its neighbors (called kernel diff in this script) is compared between the tiles*\n\n\u003e *The fact that the tiles are shrunk before comparison is actually important for this to function. This is what allows matches to be 'fuzzy'. If we don't shrink the tiles before comparison, then the quality of the matches goes way down.*\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eTarget Image\u003c/th\u003e\n    \u003cth\u003e\u003c/th\u003e\n    \u003cth\u003eTiles compared by pixel with the target\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\example_image.jpg\" height=300 \u003e \u003cbr/\u003e\u0026nbsp\n    \u003c/td\u003e\n    \u003ctd\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/td\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\mosaic_16x16_O0.0_so0.0.jpg\" height=300\u003e \n      \u003cbr/\u003e\u003cbr/\u003e\u003csup\u003e\n\n`-O 0.0 -so 0.0`\n\n\u003c/sup\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nNotice how each tile provides more than one pixel's worth of information (for the target image).  \nMultiple tiles come together to form shapes as well as colors, *and* each individual tile is completely unaltered, preserving their 'authenticity'.\n\n\n\u003cbr/\u003e\n\n\n\n### A more subtle overlay:\nFinally, in order to get a little more clarity and more vibrant colors, we can cheat using a modified, more subtle version of the overlay method shown above.\n\nWe can take the target image, cut it up into tiles, and blur each tile separately to remove the obvious edges that ruin the effect in the \"simple overlay\" example above.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eOnly the overlay\u003c/th\u003e\n    \u003cth\u003e\u003c/th\u003e\n    \u003cth\u003eTiles + subtle overlay\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\mosaic_16x16_l0.0_k0.0_r0.0_O0.0_so1.0.jpg\" height=300 \u003e \u003cbr/\u003e\u0026nbsp\n    \u003c/td\u003e\n    \u003ctd\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/br\u003e\u003e\u003c/td\u003e\n    \u003ctd align=center\u003e\n      \u003cimg src=\"misc\\images\\mosaic_16x16_so0.6.jpg\" height=300\u003e \n      \u003cbr/\u003e\u003cbr/\u003e\u003csup\u003e\n\n`-so 0.6`\n\n\u003c/sup\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nThe effect is subtle, but the colors pop a little more, and the original image can be seen slightly clearer, despite the low tile resolution, and the absence of any clear added lines in any of the tiles.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecho-lalia%2Fhd-mosaic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fecho-lalia%2Fhd-mosaic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecho-lalia%2Fhd-mosaic/lists"}