Created
January 7, 2023 23:03
-
-
Save Nakilon/357dc62cb726b1ec0c04c74afc856840 to your computer and use it in GitHub Desktop.
вс, 16 мар. 2014 г., 08:49
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> // malloc | |
#include <string.h> // memcpy | |
#include <math.h> // sin cos | |
struct scrimage { | |
int width, height; | |
unsigned** pixels; | |
}; | |
struct scrimage* scread(const char* filename) | |
{ | |
FILE* file = fopen(filename, "rb"); | |
struct scrimage* ptr = malloc(sizeof(struct scrimage)); | |
fseek(file, 10, SEEK_SET); | |
unsigned offset; | |
fread(&offset, sizeof(int), 1, file); | |
printf("pixel array offset: %d\n", offset); | |
unsigned header_size; | |
fread(&header_size, sizeof(int), 1, file); | |
printf("header size: %d\n", header_size); | |
switch (header_size) { | |
case 0x7C: // BITMAPV5HEADER | |
case 0x28: // BITMAPINFOHEADER | |
fread(&(ptr->width), sizeof(int), 1, file); | |
fread(&(ptr->height), sizeof(int), 1, file); | |
break; | |
default: | |
printf("unknown header size\n"); | |
exit(1); | |
} | |
printf("width, height: %d, %d\n", ptr->width, ptr->height); | |
unsigned short bitcount; | |
fread(&bitcount, sizeof(unsigned short), 1, file); // color planes | |
fread(&bitcount, sizeof(unsigned short), 1, file); | |
printf("bpp: %d\n", bitcount); | |
fseek(file, offset, SEEK_SET); | |
ptr->pixels = malloc(sizeof(int*) * abs(ptr->height)); | |
for (int i = ptr->height > 0 ? ptr->height - 1 : 0, n = abs(ptr->height); n--; --i) { | |
ptr->pixels[abs(i)] = calloc(ptr->width, sizeof(int)); | |
for (int j = 0; j < ptr->width; ++j) | |
fread(&(ptr->pixels[abs(i)][j]), sizeof(char), bitcount / 8, file); | |
// TODO 4 bytes aligning | |
} | |
ptr->height = abs(ptr->height); | |
fclose(file); | |
printf("scread('%s')\n", filename); | |
return ptr; | |
} | |
void scwrite(struct scrimage* image, char* filename) | |
{ | |
FILE* file = fopen(filename, "wb"); | |
fwrite("BM", sizeof(char), 2, file); | |
int t = 14 + 12 + image->height * image->width * sizeof(int); | |
fwrite(&t, sizeof(int), 1, file); | |
t = 0; fwrite(&t, sizeof(int), 1, file); | |
t = 26; fwrite(&t, sizeof(int), 1, file); | |
t = 12; fwrite(&t, sizeof(int), 1, file); | |
fwrite(&(image->width), sizeof(short int), 1, file); | |
fwrite(&(image->height), sizeof(short int), 1, file); | |
t = 1; fwrite(&t, sizeof(short int), 1, file); | |
t = 32; fwrite(&t, sizeof(short int), 1, file); | |
for (int i = image->height; i--; ) | |
fwrite(image->pixels[i], sizeof(int), image->width, file); | |
fclose(file); | |
printf("scwrite('%s')\n", filename); | |
} | |
struct scrimage* map_image_with_params(struct scrimage* image, int lambda(), int argc, int* argv) | |
{ | |
struct scrimage* ptr = malloc(sizeof(struct scrimage)); | |
ptr->width = image->width; | |
ptr->height = image->height; | |
ptr->pixels = malloc(sizeof(int*) * ptr->height); | |
for (int i = 0; i < ptr->height; ++i) { | |
ptr->pixels[i] = malloc(sizeof(int) * ptr->width); | |
for (int j = 0; j < ptr->width; ++j) | |
switch (argc) { | |
case 0: ptr->pixels[i][j] = lambda(image->pixels[i][j] ); break; | |
case 2: ptr->pixels[i][j] = lambda(image->pixels[i][j], argv[0], argv[1]); break; | |
default: printf("unsupported number of args (%d) in lambda\n", argc); exit(1); | |
} | |
} | |
printf("map_image()\n"); | |
return ptr; | |
} | |
struct scrimage* map_image(struct scrimage* image, int lambda()) | |
{ | |
int t[1]; | |
return map_image_with_params(image, lambda, 0, t); | |
} | |
struct scrimage* sclone(struct scrimage* image) | |
{ | |
struct scrimage* ptr = malloc(sizeof(struct scrimage)); | |
ptr->width = image->width; | |
ptr->height = image->height; | |
ptr->pixels = malloc(sizeof(int*) * ptr->height); | |
for (int i = 0; i < ptr->height; ++i) { | |
ptr->pixels[i] = malloc(sizeof(int) * ptr->width); | |
memcpy(ptr->pixels[i], image->pixels[i], sizeof(int) * ptr->width); | |
} | |
printf("sclone()\n"); | |
return ptr; | |
} | |
struct scrimage* filter_min(struct scrimage* image) | |
{ | |
struct scrimage* ptr = malloc(sizeof(struct scrimage)); | |
ptr->width = image->width; | |
ptr->height = image->height; | |
ptr->pixels = malloc(sizeof(int*) * ptr->height); | |
for (int i1 = 0; i1 < ptr->height; ++i1) { | |
ptr->pixels[i1] = malloc(sizeof(int) * ptr->width); | |
for (int j1 = 0; j1 < ptr->width; ++j1) { | |
ptr->pixels[i1][j1] = 1000000000; | |
for (int i2 = -2; i2 < 3; ++i2) | |
for (int j2 = -2; j2 < 3; ++j2) { | |
if (i1 + i2 < 0 || i1 + i2 >= ptr->height) continue; | |
if (j1 + j2 < 0 || j1 + j2 >= ptr->width) continue; | |
if (image->pixels[i1 + i2][j1 + j2] < ptr->pixels[i1][j1]) | |
ptr->pixels[i1][j1] = image->pixels[i1 + i2][j1 + j2]; | |
} | |
} | |
} | |
printf("filter_min()\n"); | |
return ptr; | |
} | |
int rgb2hsv(int pixel) | |
{ | |
float b = ( pixel & 0xFF) / 256.0; | |
float g = ((pixel>> 8) & 0xFF) / 256.0; | |
float r = ((pixel>>16) & 0xFF) / 256.0; | |
float max = b > g ? b > r ? b : r : g > r ? g : r; | |
float min = b < g ? b < r ? b : r : g < r ? g : r; | |
unsigned char v = 255 * max; | |
unsigned char s = 255 * (max == 0 ? 0 : (1 - min/max)); | |
float hf = (max == min ? 0 : | |
max == g ? ((b - r) / (max - min)) + 120 : | |
max == b ? ((b - r) / (max - min)) + 240 : | |
max == r && g >= b ? ((g - b) / (max - min)) : | |
max == r && g < b ? ((g - b) / (max - min)) + 360 : -1); | |
if (hf == -1) { printf("can't convert RGB(%x) to HSV\n", pixel); exit(1); } | |
unsigned char h = hf / 360 * 255; | |
return (((h << 8) + s) << 8) + v; | |
} | |
int hsv2rgb(int pixel) | |
{ | |
float v = ( pixel & 0xFF) / 256.0 * 100; | |
float s = ((pixel>> 8) & 0xFF) / 256.0 * 100; | |
char h = ((pixel>>16) & 0xFF) / 256.0 * 360 / 60; | |
float vmin = (100 - s) * v / 100; | |
float a = (v - vmin) * (h % 60) / 60; | |
float vinc = vmin + a; | |
float vdec = v - a; | |
float rf, gf, bf; | |
switch (h) { | |
case 0: rf = v; gf = vinc; bf = vmin; break; | |
case 1: rf = vdec; gf = v; bf = vmin; break; | |
case 2: rf = vmin; gf = v; bf = vinc; break; | |
case 3: rf = vmin; gf = vdec; bf = v; break; | |
case 4: rf = vinc; gf = vmin; bf = v; break; | |
case 5: rf = v; gf = vmin; bf = vdec; break; | |
default: printf("%d\n", h); exit(1); | |
} | |
unsigned char r = rf * 255 / 100; | |
unsigned char g = gf * 255 / 100; | |
unsigned char b = bf * 255 / 100; | |
return (((r << 8) + g) << 8) + b; | |
} | |
struct scrimage* rgb2hsv_opt(struct scrimage *image) | |
{ | |
struct scrimage* ptr = malloc(sizeof(struct scrimage)); | |
struct scrimage* temp_hsv = map_image(image, rgb2hsv); | |
ptr->width = image->width; | |
ptr->height = image->height; | |
ptr->pixels = malloc(sizeof(int*) * ptr->height); | |
for (int i = 0; i < ptr->height; ++i) { | |
ptr->pixels[i] = malloc(sizeof(int) * ptr->width * 3); | |
for (int j = 0; j < ptr->width; ++j) { | |
unsigned hsv = temp_hsv->pixels[i][j]; | |
ptr->pixels[i][j*3 ] = hsv >> 20 & 0xF; | |
ptr->pixels[i][j*3+1] = hsv >> 12 & 0xF; | |
ptr->pixels[i][j*3+2] = hsv >> 4 & 0xF; } | |
} | |
printf("map_image()\n"); | |
return ptr; | |
} | |
int int2heat(int value, int min, int max) | |
{ | |
float n = (value - min) * 1.0 / (max - min); | |
unsigned char t = sqrt(sqrt(sqrt(sqrt(n > 1 ? 1 : n)))) * 255; | |
return (t << 16) + (t << 8) + t; | |
} | |
int main(int argc, const char * argv[]) | |
{ | |
setbuf(stdout, NULL); | |
printf("arguments:"); | |
for (int i = 0; i < argc; ++i) | |
printf(" %s", argv[i]); | |
printf("\n"); | |
struct scrimage* screenshot = scread(argv[1]); | |
scwrite(map_image(map_image(screenshot, rgb2hsv), hsv2rgb), "clone.screenshot.bmp"); | |
struct scrimage* sample = scread(argv[2]); | |
scwrite(sample, "clone.sample.bmp"); | |
unsigned char distances[16][16][16][16][16]; | |
for (int s1 = 0; s1 < 16; ++s1) | |
for (int v1 = 0; v1 < 16; ++v1) | |
for (int h2 = 0; h2 < 16; ++h2) | |
for (int s2 = 0; s2 < 16; ++s2) | |
for (int v2 = 0; v2 < 16; ++v2) { | |
float x1 = v1 * s1 / 16.0; | |
float y1 = v1; | |
float z1 = 0; | |
float x2 = v2 * s2 / 16.0 * cos(h2 * 2*3.1415926 / 16); | |
float y2 = v2; | |
float z2 = v2 * s2 / 16.0 * sin(h2 * 2*3.1415926 / 16); | |
distances[s1][v1][h2][s2][v2] = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)); | |
} | |
/* | |
printf("%d\n", (unsigned)(distances[1][15][0][1][15])); | |
printf("%d\n", (unsigned)(distances[1][15][4][1][15])); | |
printf("%d\n", (unsigned)(distances[1][15][8][1][15])); | |
printf("%d\n", (unsigned)(distances[1][15][12][1][15])); | |
printf("%d\n", (unsigned)(distances[15][15][0][0][8])); | |
printf("%d\n", (unsigned)(distances[15][15][8][15][15])); | |
*/ | |
struct scrimage* screenshot_hsv = map_image(screenshot, rgb2hsv); | |
struct scrimage* sample_hsv_opt = rgb2hsv_opt(sample); | |
struct scrimage* map = sclone(screenshot_hsv); | |
sample_hsv_opt->width /= 2; | |
sample_hsv_opt->height /= 2; | |
unsigned* sample_hsv_1d = malloc(sample_hsv_opt->height * sample_hsv_opt->width * sizeof(int) * 3); | |
for (int i = 0; i < sample_hsv_opt->height; ++i) | |
memcpy(sample_hsv_1d + sample_hsv_opt->width * i * 3, sample_hsv_opt->pixels[i], sample_hsv_opt->width * sizeof(int) * 3); | |
unsigned min = 1000000000; | |
unsigned max = 0; | |
for (int i1 = 0; i1 < map->height; ++i1) { | |
printf("%d/%d... ", i1, min); | |
for (int j1 = 0; j1 < map->width; ++j1) { | |
if (i1 + sample_hsv_opt->height - 1 >= map->height || | |
j1 + sample_hsv_opt->width - 1 >= map->width) { | |
map->pixels[i1][j1] = -1; | |
continue; | |
} | |
map->pixels[i1][j1] = 0; | |
unsigned* sample_hsv_1d_ptr = sample_hsv_1d; | |
for (int i2 = 0; i2 < sample_hsv_opt->height; ++i2) | |
for (int j2 = 0; j2 < sample_hsv_opt->width; ++j2) { | |
if (map->pixels[i1][j1] > min) goto A; | |
int c1 = screenshot_hsv->pixels[i1+i2][j1+j2]; | |
int h2 = sample_hsv_1d_ptr[0]; | |
int s2 = sample_hsv_1d_ptr[1]; | |
int v2 = sample_hsv_1d_ptr[2]; | |
sample_hsv_1d_ptr += 3; | |
map->pixels[i1][j1] += distances\ | |
[c1 >> 12 & 0xF]\ | |
[c1 >> 4 & 0xF]\ | |
[(h2 - (c1 >> 20 & 0xF)) % 16]\ | |
[s2]\ | |
[v2]; | |
} | |
A: | |
if (map->pixels[i1][j1] > max) max = map->pixels[i1][j1]; | |
if (map->pixels[i1][j1] < min) min = map->pixels[i1][j1]; | |
} | |
} | |
printf("\n"); | |
printf("min/max color distance: %d/%d\n", min, max); | |
for (int i = 0; i < map->height; ++i) | |
for (int j = 0; j < map->width; ++j) | |
if (map->pixels[i][j] == -1) | |
map->pixels[i][j] = max; | |
int t[] = {min, max}; | |
scwrite(map_image_with_params(filter_min(filter_min(filter_min(map))), int2heat, 2, t), "heat.bmp"); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment