├── .gitignore ├── ASDFPixelSort.pde ├── README.md ├── data └── mountains.jpg ├── mountains_0.jpg ├── mountains_1.jpg ├── mountains_2.jpg └── mountains_3.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /ASDFPixelSort.pde: -------------------------------------------------------------------------------- 1 | 2 | /******** 3 | 4 | ASDF Pixel Sort 5 | Kim Asendorf | 2010 | kimasendorf.com 6 | 7 | Sorting modes 8 | 0 = white 9 | 1 = black 10 | 2 = bright 11 | 3 = dark 12 | 13 | */ 14 | 15 | int mode = 0; 16 | 17 | // image path is relative to sketch directory 18 | PImage img; 19 | String imgFileName = "mountains"; 20 | String fileType = "jpg"; 21 | 22 | int loops = 1; 23 | 24 | // threshold values to determine sorting start and end pixels 25 | // using the absolute rgb value 26 | // r*g*b = 255*255*255 = 16581375 27 | // 0 = white 28 | // -16581375 = black 29 | // sort all pixels whiter than the threshold 30 | int whiteValue = -12345678; 31 | // sort all pixels blacker than the threshold 32 | int blackValue = -3456789; 33 | // using the brightness value 34 | // sort all pixels brighter than the threshold 35 | int brightValue = 127; 36 | // sort all pixels darker than the threshold 37 | int darkValue = 223; 38 | 39 | 40 | int row = 0; 41 | int column = 0; 42 | 43 | boolean saved = false; 44 | 45 | void setup() { 46 | img = loadImage(imgFileName + "." + fileType); 47 | 48 | // use only numbers (not variables) for the size() command, Processing 3 49 | size(1, 1); 50 | 51 | // allow resize and update surface to image dimensions 52 | surface.setResizable(true); 53 | surface.setSize(img.width, img.height); 54 | 55 | // load image onto surface - scale to the available width,height for display 56 | image(img, 0, 0, width, height); 57 | } 58 | 59 | 60 | void draw() { 61 | 62 | if (frameCount <= loops) { 63 | 64 | // loop through columns 65 | println("Sorting Columns"); 66 | while (column < img.width-1) { 67 | img.loadPixels(); 68 | sortColumn(); 69 | column++; 70 | img.updatePixels(); 71 | } 72 | 73 | // loop through rows 74 | println("Sorting Rows"); 75 | while (row < img.height-1) { 76 | img.loadPixels(); 77 | sortRow(); 78 | row++; 79 | img.updatePixels(); 80 | } 81 | } 82 | 83 | // load updated image onto surface and scale to fit the display width and height 84 | image(img, 0, 0, width, height); 85 | 86 | if (!saved && frameCount >= loops) { 87 | // save img 88 | img.save(imgFileName + "_" + mode + ".png"); 89 | 90 | saved = true; 91 | println("Saved frame " + frameCount); 92 | 93 | // exiting here can interrupt file save, wait for user to trigger exit 94 | println("Click or press any key to exit..."); 95 | } 96 | } 97 | 98 | void keyPressed() { 99 | if (saved) { 100 | System.exit(0); 101 | } 102 | } 103 | 104 | void mouseClicked() { 105 | if (saved) { 106 | System.exit(0); 107 | } 108 | } 109 | 110 | void sortRow() { 111 | // current row 112 | int y = row; 113 | 114 | // where to start sorting 115 | int x = 0; 116 | 117 | // where to stop sorting 118 | int xEnd = 0; 119 | 120 | while (xEnd < img.width-1) { 121 | switch (mode) { 122 | case 0: 123 | x = getFirstNoneWhiteX(x, y); 124 | xEnd = getNextWhiteX(x, y); 125 | break; 126 | case 1: 127 | x = getFirstNoneBlackX(x, y); 128 | xEnd = getNextBlackX(x, y); 129 | break; 130 | case 2: 131 | x = getFirstNoneBrightX(x, y); 132 | xEnd = getNextBrightX(x, y); 133 | break; 134 | case 3: 135 | x = getFirstNoneDarkX(x, y); 136 | xEnd = getNextDarkX(x, y); 137 | break; 138 | default: 139 | break; 140 | } 141 | 142 | if (x < 0) break; 143 | 144 | int sortingLength = xEnd-x; 145 | 146 | color[] unsorted = new color[sortingLength]; 147 | color[] sorted = new color[sortingLength]; 148 | 149 | for (int i = 0; i < sortingLength; i++) { 150 | unsorted[i] = img.pixels[x + i + y * img.width]; 151 | } 152 | 153 | sorted = sort(unsorted); 154 | 155 | for (int i = 0; i < sortingLength; i++) { 156 | img.pixels[x + i + y * img.width] = sorted[i]; 157 | } 158 | 159 | x = xEnd+1; 160 | } 161 | } 162 | 163 | 164 | void sortColumn() { 165 | // current column 166 | int x = column; 167 | 168 | // where to start sorting 169 | int y = 0; 170 | 171 | // where to stop sorting 172 | int yEnd = 0; 173 | 174 | while (yEnd < img.height-1) { 175 | switch (mode) { 176 | case 0: 177 | y = getFirstNoneWhiteY(x, y); 178 | yEnd = getNextWhiteY(x, y); 179 | break; 180 | case 1: 181 | y = getFirstNoneBlackY(x, y); 182 | yEnd = getNextBlackY(x, y); 183 | break; 184 | case 2: 185 | y = getFirstNoneBrightY(x, y); 186 | yEnd = getNextBrightY(x, y); 187 | break; 188 | case 3: 189 | y = getFirstNoneDarkY(x, y); 190 | yEnd = getNextDarkY(x, y); 191 | break; 192 | default: 193 | break; 194 | } 195 | 196 | if (y < 0) break; 197 | 198 | int sortingLength = yEnd-y; 199 | 200 | color[] unsorted = new color[sortingLength]; 201 | color[] sorted = new color[sortingLength]; 202 | 203 | for (int i = 0; i < sortingLength; i++) { 204 | unsorted[i] = img.pixels[x + (y+i) * img.width]; 205 | } 206 | 207 | sorted = sort(unsorted); 208 | 209 | for (int i = 0; i < sortingLength; i++) { 210 | img.pixels[x + (y+i) * img.width] = sorted[i]; 211 | } 212 | 213 | y = yEnd+1; 214 | } 215 | } 216 | 217 | 218 | // white x 219 | int getFirstNoneWhiteX(int x, int y) { 220 | while (img.pixels[x + y * img.width] < whiteValue) { 221 | x++; 222 | if (x >= img.width) return -1; 223 | } 224 | return x; 225 | } 226 | 227 | int getNextWhiteX(int x, int y) { 228 | x++; 229 | while (img.pixels[x + y * img.width] > whiteValue) { 230 | x++; 231 | if (x >= img.width) return img.width-1; 232 | } 233 | return x-1; 234 | } 235 | 236 | // black x 237 | int getFirstNoneBlackX(int x, int y) { 238 | while (img.pixels[x + y * img.width] > blackValue) { 239 | x++; 240 | if (x >= img.width) return -1; 241 | } 242 | return x; 243 | } 244 | 245 | int getNextBlackX(int x, int y) { 246 | x++; 247 | while (img.pixels[x + y * img.width] < blackValue) { 248 | x++; 249 | if (x >= img.width) return img.width-1; 250 | } 251 | return x-1; 252 | } 253 | 254 | // bright x 255 | int getFirstNoneBrightX(int x, int y) { 256 | while (brightness(img.pixels[x + y * img.width]) < brightValue) { 257 | x++; 258 | if (x >= img.width) return -1; 259 | } 260 | return x; 261 | } 262 | 263 | int getNextBrightX(int x, int y) { 264 | x++; 265 | while (brightness(img.pixels[x + y * img.width]) > brightValue) { 266 | x++; 267 | if (x >= img.width) return img.width-1; 268 | } 269 | return x-1; 270 | } 271 | 272 | // dark x 273 | int getFirstNoneDarkX(int x, int y) { 274 | while (brightness(img.pixels[x + y * img.width]) > darkValue) { 275 | x++; 276 | if (x >= img.width) return -1; 277 | } 278 | return x; 279 | } 280 | 281 | int getNextDarkX(int x, int y) { 282 | x++; 283 | while (brightness(img.pixels[x + y * img.width]) < darkValue) { 284 | x++; 285 | if (x >= img.width) return img.width-1; 286 | } 287 | return x-1; 288 | } 289 | 290 | // white y 291 | int getFirstNoneWhiteY(int x, int y) { 292 | if (y < img.height) { 293 | while (img.pixels[x + y * img.width] < whiteValue) { 294 | y++; 295 | if (y >= img.height) return -1; 296 | } 297 | } 298 | return y; 299 | } 300 | 301 | int getNextWhiteY(int x, int y) { 302 | y++; 303 | if (y < img.height) { 304 | while (img.pixels[x + y * img.width] > whiteValue) { 305 | y++; 306 | if (y >= img.height) return img.height-1; 307 | } 308 | } 309 | return y-1; 310 | } 311 | 312 | 313 | // black y 314 | int getFirstNoneBlackY(int x, int y) { 315 | if (y < img.height) { 316 | while (img.pixels[x + y * img.width] > blackValue) { 317 | y++; 318 | if (y >= img.height) return -1; 319 | } 320 | } 321 | return y; 322 | } 323 | 324 | int getNextBlackY(int x, int y) { 325 | y++; 326 | if (y < img.height) { 327 | while (img.pixels[x + y * img.width] < blackValue) { 328 | y++; 329 | if (y >= img.height) return img.height-1; 330 | } 331 | } 332 | return y-1; 333 | } 334 | 335 | // bright y 336 | int getFirstNoneBrightY(int x, int y) { 337 | if (y < img.height) { 338 | while (brightness(img.pixels[x + y * img.width]) < brightValue) { 339 | y++; 340 | if (y >= img.height) return -1; 341 | } 342 | } 343 | return y; 344 | } 345 | 346 | int getNextBrightY(int x, int y) { 347 | y++; 348 | if (y < img.height) { 349 | while (brightness(img.pixels[x + y * img.width]) > brightValue) { 350 | y++; 351 | if (y >= img.height) return img.height-1; 352 | } 353 | } 354 | return y-1; 355 | } 356 | 357 | // dark y 358 | int getFirstNoneDarkY(int x, int y) { 359 | if (y < img.height) { 360 | while (brightness(img.pixels[x + y * img.width]) > darkValue) { 361 | y++; 362 | if (y >= img.height) return -1; 363 | } 364 | } 365 | return y; 366 | } 367 | 368 | int getNextDarkY(int x, int y) { 369 | y++; 370 | if (y < img.height) { 371 | while (brightness(img.pixels[x + y * img.width]) < darkValue) { 372 | y++; 373 | if (y >= img.height) return img.height-1; 374 | } 375 | } 376 | return y-1; 377 | } 378 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASDFPixelSort 2 | 3 | Processing script to sort portions of pixels in an image with threshold control. 4 | 5 | ![Mode 0](./mountains_0.jpg) 6 | ![Mode 1](./mountains_1.jpg) 7 | ![Mode 2](./mountains_2.jpg) 8 | ![Mode 3](./mountains_3.jpg) 9 | 10 | Kim Asendorf 2010 11 | https://kimasendorf.com -------------------------------------------------------------------------------- /data/mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimasendorf/ASDFPixelSort/d7b1ec40653f5386e3595e86657aecf9c46e5e64/data/mountains.jpg -------------------------------------------------------------------------------- /mountains_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimasendorf/ASDFPixelSort/d7b1ec40653f5386e3595e86657aecf9c46e5e64/mountains_0.jpg -------------------------------------------------------------------------------- /mountains_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimasendorf/ASDFPixelSort/d7b1ec40653f5386e3595e86657aecf9c46e5e64/mountains_1.jpg -------------------------------------------------------------------------------- /mountains_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimasendorf/ASDFPixelSort/d7b1ec40653f5386e3595e86657aecf9c46e5e64/mountains_2.jpg -------------------------------------------------------------------------------- /mountains_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimasendorf/ASDFPixelSort/d7b1ec40653f5386e3595e86657aecf9c46e5e64/mountains_3.jpg --------------------------------------------------------------------------------