Skip to content

Instantly share code, notes, and snippets.

@Nakilon
Created January 7, 2023 23:03
Show Gist options
  • Save Nakilon/357dc62cb726b1ec0c04c74afc856840 to your computer and use it in GitHub Desktop.
Save Nakilon/357dc62cb726b1ec0c04c74afc856840 to your computer and use it in GitHub Desktop.
вс, 16 мар. 2014 г., 08:49
#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