-
Notifications
You must be signed in to change notification settings - Fork 0
/
artify.c
139 lines (124 loc) · 5.66 KB
/
artify.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
struct letter {
char letter;
unsigned char** image;
int img_width, img_height;
};
// evaluates the average difference of a character image's and the input image's pixels
float difference(int x, int y, struct letter chr, size_t img_width, size_t img_height, unsigned char image[img_height][img_width]){
if (x+chr.img_width>=img_width || y+chr.img_height>=img_height)
return -1.0;
float accu = 0.0;
int i,j;
i=j=0;
for (; i<chr.img_height; i++) {
j=0;
for(; j<chr.img_width; j++) {
accu += (float) abs(chr.image[i][j]-image[y+i][x+j]);
}
}
return accu/(i*j);
}
// evlatuates the appropriate character for a specific position in the image
char chooseLetter(int* x, int* y, size_t img_width, size_t img_height, unsigned char image[img_height][img_width], struct letter* letters, int numberOfLetters){
struct letter best;
float leastDif = NAN;
float divisor = 2.5f; // equivilant to resolution and size (high divisor -> large result; small divisor -> small result)
// iterate through all characters
for (int i=0; i<numberOfLetters; i++) {
struct letter cur = letters[i];
float curDif = difference(*x, *y, cur, img_width, img_height, image);
if (curDif > -1.0)
if (isnan(leastDif) || curDif < leastDif) {
leastDif = curDif;
best = cur;
}
}
// a character was found
if(!isnan(leastDif)) {
*x += (int) best.img_width/divisor;
return best.letter;
}
// no character matched so newline
*x = 0;
*y +=(int) letters->img_height/divisor;
return '\n';
}
// convert an image to similar string
char* imgToStr(size_t img_width, size_t img_height, unsigned char image[img_height][img_width], struct letter* letters, int numberOfLetters){
char* result = malloc(img_height*img_width*sizeof(char));
int x, y, i;
x=y=i=0;
while (y<img_height) { //append character until the end
result[i++]=chooseLetter(&x, &y, img_width, img_height, image, letters, numberOfLetters);
printf("%c",result[i-1]);
}
result[i]='\0';
return result;
}
int main(int argc, char** argv){
int filter=127;
if (argc < 2 || argc > 3) {
fprintf(stderr, "USAGE: %s <JPEG to artify> [optionally: filter-threshold (0-255) -- default: 127]\n", argv[0]);
return 1;
} else if (argc == 3)
filter = atoi(argv[2]);
// loading the image
int width, height, n;
unsigned char* img = stbi_load(argv[1], &width, &height, &n, 1);
// converting the one-dimensional-image data to a two-dim. array
unsigned char pixels[height][width];
for (int i=0; i<height; i++)
for (int j=0; j<width; j++)
// pixels[i][j]=img[i*width+j]; // for without a filter
if (img[i*width+j]>filter)
pixels[i][j]=255;
else
pixels[i][j]=0;
// prepare letters
// open alphabet directory
DIR *d;
struct dirent *dir;
d=opendir("unicode_alphabet");
int number_of_letters=0;
struct letter* alphabet = malloc(100 * sizeof(struct letter));
if (d) {
int i=0;
// iterate through every file
while ((dir = readdir(d)) != NULL) {
if (*(dir->d_name) == 0x2E) // if the file is not hidden
continue;
// collect data of alphabet-file
int dim;
char* path = (char*) calloc(24, sizeof(char));
sprintf(path, "unicode_alphabet/%s", dir->d_name);
unsigned char* letter_raw = stbi_load(path, &(alphabet+i)->img_width, &(alphabet+i)->img_height, &dim, 1);
char* file_letter=malloc(sizeof(char*));
int chr_index = 0;
while (*((dir->d_name)+chr_index) != 0x2E && *((dir->d_name)+chr_index) != '\0') { // split the filename by the extension -- so only the char-integer is in file_letter
*(file_letter+chr_index) = *((dir->d_name)+chr_index);
chr_index++;
}
(alphabet+i)->letter = atoi(file_letter);
// convert the one-dimensional image data into a two-dimensional one
(alphabet+i)->image= malloc((alphabet+i)->img_height*sizeof(unsigned char*));
for (int y=0; y<(alphabet+i)->img_height; y++) {
*((alphabet+i)->image+y) = malloc((alphabet+i)->img_width*sizeof(unsigned char));
memcpy(*((alphabet+i)->image+y), letter_raw+((alphabet+i)->img_width*y), (alphabet+i)->img_width);
}
i++;
}
number_of_letters=i;
}
char* result = imgToStr(width, height, pixels, alphabet, number_of_letters);
// save result to file
FILE *fp = fopen("output/result.txt", "w");
fprintf(fp, "%s",result);
fclose(fp);
return 0;
}