{"id":20384325,"url":"https://github.com/gyakobo/quadtree-image-compression","last_synced_at":"2025-04-12T09:22:59.224Z","repository":{"id":262007308,"uuid":"807852326","full_name":"Gyakobo/quadtree-image-compression","owner":"Gyakobo","description":"This project aims utilize a graph(a tree) as a form of image value compression by implementing a special kind of data structure where it basically groups repeating variables into a node and ungroups non-repeating values into their own nodes.","archived":false,"fork":false,"pushed_at":"2025-01-31T07:45:17.000Z","size":146,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-26T04:21:43.785Z","etag":null,"topics":["c","c-plus-plus","compression-algorithm","dynamic-programming","grayscale-images","malloc","njit","partitioning","pointers-and-arrays","rgb","tree-structure","weissman-score"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Gyakobo.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-05-29T22:41:49.000Z","updated_at":"2025-01-31T07:45:20.000Z","dependencies_parsed_at":"2024-11-09T21:30:55.322Z","dependency_job_id":"874f4b05-3f92-4e5d-bd04-4a2ee4347f15","html_url":"https://github.com/Gyakobo/quadtree-image-compression","commit_stats":null,"previous_names":["gyakobo/quadtree-image-compression"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyakobo%2Fquadtree-image-compression","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyakobo%2Fquadtree-image-compression/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyakobo%2Fquadtree-image-compression/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyakobo%2Fquadtree-image-compression/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gyakobo","download_url":"https://codeload.github.com/Gyakobo/quadtree-image-compression/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248544373,"owners_count":21121940,"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":["c","c-plus-plus","compression-algorithm","dynamic-programming","grayscale-images","malloc","njit","partitioning","pointers-and-arrays","rgb","tree-structure","weissman-score"],"created_at":"2024-11-15T02:27:21.929Z","updated_at":"2025-04-12T09:22:59.209Z","avatar_url":"https://github.com/Gyakobo.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Quadtree Image Compression\r\n\r\n![image](https://img.shields.io/badge/C-00599C?style=for-the-badge\u0026logo=c\u0026logoColor=white)\r\n![image](https://img.shields.io/badge/C%2B%2B-00599C?style=for-the-badge\u0026logo=c%2B%2B\u0026logoColor=white)\r\n![image](https://img.shields.io/badge/CMake-064F8C?style=for-the-badge\u0026logo=cmake\u0026logoColor=white)\r\n![image](https://img.shields.io/badge/windows%20terminal-4D4D4D?style=for-the-badge\u0026logo=windows%20terminal\u0026logoColor=white)\r\n\r\nAuthor: [Andrew Gyakobo](https://github.com/Gyakobo)\r\n\r\n\u003e[!NOTE]\r\n\u003eEach processed image file by default have to be in a form of a square in order to be processed\r\n\r\n\u003e[!WARNING]\r\n\u003eThis project hasn't yet been tested as of late and is still in development. I'd personally love to add a pre-order traversal decoder to this project on par with the encoder program. I'd also love to compare to my other compression algorithm [sparse matrix](https://github.com/Gyakobo/sparse_matrix).\r\n\r\n\r\nThis project aims utilize a graph(a tree) as a form of two-dimensional image compression by implementing a special kind of data structure where it basically groups repeating variables into a node and ungroups non-repeating values into their own nodes.\r\n\r\n## Introduction\r\n\r\nIn this example specifically we shall be compressing a grayscale image. Given that pixels are usually stored as a series of integers, we would be using the `int` type to store said pixels.\r\n\r\n## Methodology\r\n\r\nOne method to compress an image is to store it in a tree data structure where each node would have up to 4 children. Each of them shall represent a select partition of the image in one of the four quartiles: northwest, northeast, southwest, and southeast. Needless to say, the root node marked with a `-1` will either represent the entire image or another subset of partitions. The partitioning process will continue till each node in the partitioned subset carries the same color intensity. \r\n\r\n1) Let's consider the following image content from the given [input.txt](https://github.com/Gyakobo/tree-image-compression/blob/main/input.txt):\r\n\r\n| 3 | 3 | 3 | 3 | 2 | 2 | 1 | 1 |\r\n|---|---|---|---|---|---|---|---|\r\n| 3 | 3 | 3 | 3 | 2 | 2 | 1 | 1 |\r\n| 3 | 3 | 3 | 3 | 0 | 5 | 1 | 0 |\r\n| 3 | 3 | 3 | 3 | 0 | 0 | 0 | 2 |\r\n| 1 | 1 | 1 | 1 | 1 | 1 | 0 | 3 |\r\n| 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |\r\n| 1 | 1 | 1 | 1 | 5 | 5 | 0 | 0 |\r\n| 1 | 1 | 1 | 1 | 5 | 5 | 0 | 0 |\r\n\r\n\u003e[!NOTE]\r\n\u003eEach 8 lines in the sample file denotes a row in the [image](https://github.com/Gyakobo/tree-image-compression/blob/main/sample.txt) file\r\n\r\n2) Assuming all the pixels are not unique, we then partition the image into equal subsets of 4 by 4 smaller images as shown by the below:\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 3 | 3 | 3 | 3 |\r\n|---|---|---|---|\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 2 | 2 | 1 | 1 |\r\n|---|---|---|---|\r\n| 2 | 2 | 1 | 1 |\r\n| 0 | 5 | 1 | 0 |\r\n| 0 | 0 | 0 | 2 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 | 1 | 1 |\r\n|---|---|---|---|\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 | 0 | 3 |\r\n|---|---|---|---|\r\n| 1 | 1 | 0 | 0 |\r\n| 5 | 5 | 0 | 0 |\r\n| 5 | 5 | 0 | 0 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n3) Afterwards we delve into the partitions more, and subsequently divide them into even smaller subsets, in this case 2 by 2 partitions. You may have noticed a recurring partain: each partition is in multiples of 2. From the getgo our partition is 8, then 4, then 2 and soon enough 1.\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 3 | 3 | 3 | 3 |\r\n|---|---|---|---|\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n\r\n\u003c/td\u003e    \u003ctd\u003e \u003ctable\u003e     \u003ctr\u003e\u003ctd\u003e\r\n\r\n| 2 | 2 |\r\n|---|---|\r\n| 2 | 2 |\r\n\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 |\r\n|---|---|\r\n| 1 | 1 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\r\n\r\n\u003ctd\u003e\r\n\r\n| 0 | 5 |\r\n|---|---|\r\n| 0 | 0 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 1 | 0 |\r\n|---|---|\r\n| 0 | 2 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e \u003c/table\u003e      \u003c/td\u003e \r\n\r\n\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 | 1 | 1 |\r\n|---|---|---|---|\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n\u003ctable\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 |\r\n|---|---|\r\n| 1 | 1 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 0 | 3 |\r\n|---|---|\r\n| 0 | 0 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 5 | 5 |\r\n|---|---|\r\n| 5 | 5 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 0 | 0 |\r\n|---|---|\r\n| 0 | 0 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\r\n\u003c/table\u003e\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n4) As the last step we make quick work of all the last non-unique variables. Judging by the remaining 10 partitions there are only 3 subsets to worked on. This shall be our final partition.\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 3 | 3 | 3 | 3 |\r\n|---|---|---|---|\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n| 3 | 3 | 3 | 3 |\r\n\r\n\u003c/td\u003e    \u003ctd\u003e \u003ctable\u003e     \u003ctr\u003e\u003ctd\u003e\r\n\r\n| 2 | 2 |\r\n|---|---|\r\n| 2 | 2 |\r\n\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 |\r\n|---|---|\r\n| 1 | 1 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\r\n\r\n\u003ctd\u003e\r\n\r\n\u003c!---\r\n| 0 | 5 |\r\n|---|---|\r\n| 0 | 0 |\r\n--\u003e\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n\u003c!--\r\n| 1 | 0 |\r\n|---|---|\r\n| 0 | 2 |\r\n--\u003e\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n\u003c/td\u003e\u003c/tr\u003e \u003c/table\u003e      \u003c/td\u003e \r\n\r\n\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 | 1 | 1 |\r\n|---|---|---|---|\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n| 1 | 1 | 1 | 1 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n\u003ctable\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 1 | 1 |\r\n|---|---|\r\n| 1 | 1 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n\u003c!--\r\n| 0 | 3 |\r\n|---|---|\r\n| 0 | 0 |\r\n--\u003e\r\n\r\n\u003ctable\u003e\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003ctd\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/td\u003e\r\n\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\r\n\u003ctr\u003e\u003ctd\u003e\r\n\r\n| 5 | 5 |\r\n|---|---|\r\n| 5 | 5 |\r\n\r\n\u003c/td\u003e\u003ctd\u003e\r\n\r\n| 0 | 0 |\r\n|---|---|\r\n| 0 | 0 |\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\r\n\u003c/table\u003e\r\n\r\n\u003c/td\u003e\u003c/tr\u003e\r\n\u003c/table\u003e\r\n\r\n5) All this partitions can thereafter be presented in the following tree below. Each node the tree shall have four other nodes representing the four partitions (NW, NE, SW, and SE order). If however the partition fully consists of pixels of the same intensity, then the node would just be labeled with such intensity.\r\n\r\n\u003cimage src=\"./assets/compression_tree.png\"\u003e\r\n\r\n\u003e[!NOTE]\r\n\u003eEach circle denotes a node with 4 other leaf nodes. Each double circle is the 'end' node with no child leaf nodes(null references).\r\n\r\n6) Finally, the image can then be encoded in a sequence of integers by performing a preorder traversal of the corresponding: \r\n\r\n| -1 | 3 | -1 | 2 | 1 |\r\n|---|---|---|---|---|\r\n| -1 | 0 | 5 | 0 | 0 |\r\n| -1 | 1 | 0 | 0 | 2 |\r\n| 1 | -1 | 1 | -1 | 0 |\r\n| 3 | 0 | 0 | 5 | 0 |\r\n\r\nYou could of course change the traversal order by just switching the places of the `preorder(root-\u003echildren[n])` functions. Hence you could even easily simulate both inorder and postorder traversals or any other traversal you may come up with.\r\n\r\n```c\r\nvoid preorder(struct Node *root) {\r\n    printf(\"d: %d\\n\", root-\u003eintensity);\r\n\r\n    if (root-\u003eintensity == -1) {\r\n        preorder(root-\u003echildren[0]);\r\n        preorder(root-\u003echildren[1]);\r\n        preorder(root-\u003echildren[2]);\r\n        preorder(root-\u003echildren[3]);\r\n    } \r\n    else {\r\n        free(root);\r\n        return;\r\n    } \r\n}\r\n```\r\n\r\n## Code snippets\r\n\r\n* The code greets you with three structs: `struct Bitmap`, `struct Node`, `struct Tree`. The `struct Bitmap` allocates space for the image and stores all of the pixel values; the `struct Node` represents a node which references four other leaf nodes; lastly, the `stuct Tree` just represents the tree data structure with a pointer to the root of the tree.  \r\n\r\n```c\r\nstruct Bitmap {\r\n    int rows;\r\n    int cols;\r\n    short *pixels;\r\n};\r\n\r\nstruct Node {\r\n    short intensity;\r\n    struct Node *children[4];\r\n};\r\n\r\nstruct Tree {\r\n    struct Node *root;\r\n};\r\n```\r\n* The `struct Tree Tree_new(struct Bitmap *b)` function along with the `create_branches(...)` function then creates the tree.\r\n\r\n## Performance\r\n\r\nWhen it comes to performance the numbers pretty much vary. If for instance an image has little to no unique values then the compression would be at its best and utmost performance. Otherwise, the compression would have varying results. \r\n\r\nIn our case the [input file](./input.txt) weights `128 bytes`, and when compressed, the [output file](./output.txt) weights just `56 bytes`. Thus so far the compressed file halved the size of the original. \r\n\r\n\u003e[!IMPORTANT]\r\n\u003eOnce again it's important to note that this compression algorithm is most prevalent when there are repeating elements in the image. \r\n\r\n## License\r\nMIT\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgyakobo%2Fquadtree-image-compression","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgyakobo%2Fquadtree-image-compression","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgyakobo%2Fquadtree-image-compression/lists"}