,.
. :%%%. .%%%.
__%%%(\ `%%%%% .%%%%%
/a ^ '% %%%% %: ,% %%"`
'__.. ,'% .-%: %-' %
~~""%:. ` % ' . `.
%% % ` %% .%: . \.
%%:. `-' ` .%% . %: :\
%(%,%..." `%, %%' %% ) )
%)%%)%%' )%%%.....- ' "/ (
%a:f%%\ % / \`% "%%% ` / \))
%(%' % /-. \ ' \ |-. '.
`' |% `() \| `()
|| / () /
() 0 | o
\ /\ o /
o ` /-|
___________ ,-/ ` _________ ,-/ _________________ INCLUDES _ OCAML _ SOURCE _ CODE _ EXAMPLES _____________________________________________

Thursday, May 15, 2014

Color Correction

As the title of this new post indicates it, we are going to see several color correction methods you can apply to an image. Basically, the color correction corresponds to a modification of the properties of the colors. In this tutorial, you will learn how to change the brightness of your image, its saturation, its contrast and I will also present the histogram equalization using the histograms of the RedGreen and Blue pixel channels and finally, we will see the logarithmic and the gamma correction.

Brightness :
n = 100
You have to know that you can increase or decrease the brightness of the pixels of your image as long as the values of the pixel components are correct. I mean that each pixel component value must be between 0 and 255.
Now if you want to increase the brightness by a coefficient n for example, all (Red,Green,Blue) pixel components must be replaced by (Red+n,Green+n,Blue+n). Note that this coefficient is generally a value between 0 and 127 or -127 and 127. Here is an example on how to implement this function :

As you may notice on my illustration, you can try to increase/decrease the brightness of a certain region of your image with different forms like a circle, a rectangle, ...

Saturation :
s = 2
Now, we will see how to change the saturation of an image. But before, what is the saturation?
In fact, this is the depth of the colors. The higher the saturation, the more vivid the colors will be.
A saturation change with a coefficient of 0 will give you a grey level of your image and a coefficient of 1 won't change anything... So let's s be the saturation coefficient of your choice and a floating point number (the best values you should try at first are the ones between 0 and 2). Here is the formula you have to use to compute all the new (Red,Green,Blue) pixel components of your image according to s :


Contrast :
n = 100
The contrast is the difference in the bright and dark areas of an image. If the contrast is high, the image looks lively; conversely, if the contrast is low, the image looks flat and monotonous. Let's n be a threshold of your choice (generally between -255 and 255), you can now compute the contrast coefficient coeff that will be used to replace all (Red,Green,Blue) pixel components by
(
 ((((Red/255) - 0.5) * coeff) + 0.5) * 255,
 ((((Green/255) - 0.5) * coeff) + 0.5) * 255,
 ((((Blue/255) - 0.5) * coeff) + 0.5) * 255
) where coeff = ((100+n) / 100)2.


Histogram equalization :
 
Before equalizing your image (= adjusting the contrast), you must know what a histogram is in image processing. You may know that a histogram is a graphical representation of the distribution of data with a horizontal x-axis and a vertical y-axis. In image processing, the values of this x-axis go from 0 to 255 and represent the different intensity levels of a RedGreen or Blue pixel component and the values of the y-axis indicate how many times a certain intensity level of a RedGreen or Blue pixel component (from the x-axis...) appears on the whole surface of your image. So the first function we must write for the equalization of any pixel channel is a function capable of generating a histogram of the Red, Green and Blue pixel channels (note that we can also generate the histogram of the grey level (= luminosity) of an image as you will see). To create a histogram, we will use a simple array of 256 indexes (representing the 256 intensity levels of the x-axis) and the content of each index will represent the distribution of these 256 intensity levels as the y-axis. All you have to do is to count the number of pixel components that have an intensity level of i and put this number at the index i of the array. It can be written like that :

As you see, I can easily get the histogram of my choice with the parameter n.
Now, we must have a function which can transform any histogram into its cumulative version.
It means that every index i of an array (representing a histogram) must contain now (the number of pixel components that have an intensity level of i) + (the number of pixel components that have an intensity level lower than i). So the last index should contain the number of pixels of your image...

We are now ready to equalize any pixel channel (note that my illustration above on the left is the result of the equalization of the 3 pixel channels). The procedure to follow is very easy. You must get the histogram of the pixel channel you want to equalize, then you have to transform this histogram into its cumulative version and finally, you just have to replace all pixel components (of the channel you want to equalize) which have an intensity level of i by
(255 * cumulative_histogram.(i)) / number of pixels of your image.
Note that if the dimensions of your image are widthxheightnumber of pixels of your image =
width * height and cumulative_histogram.(i) is the number (at the index i of an array representing a cumulative histogram) of pixel components that have an intensity level lower or equal to i.


Logarithmic correction :
The logarithmic correction is a nonlinear operation which consists in applying a logarithmic function to an image to make it brighter or darker (it depends on the function used). As we just saw that a histogram can be applied to an image, you may guess that the idea is to create a histogram which will contain the values of a certain logarithmic function and then apply this histogram to an image. Here is an example of source code where I chose to apply the logarithmic function
log(i) * (2k / log(2k)) where i is the current index of the array representing the histogram and k = 8.


Gamma correction :
γ = 0.4
The gamma correction is, like the logarithmic correction, a nonlinear operation which is generally used to make a brighter image when this image is too dark (or darker when it's too bright). This function just depends on a γ coefficient which will be used to replace all (Red,Green,Blue) pixel components of your image by (255 * (Red/255)1/γ255 * (Green/255)1/γ255 * (Blue/255)1/γ).
Note that you must use floating point numbers when you are calculating 255 * (x/255)1/γ and that the higher the γ coefficient, the more brighter the image will be. It's frequently a value between 0 and 8.

You can also observe what's happening when you apply at the same time different γ coefficients to the 3 pixel channels.

Thursday, May 8, 2014

Color Effects from LUT

The image processing topic that is going to be presented this time will be very short but it's an interesting theme which is largely used to apply specific color effects to an image. I'm talking about the LUT (Lookup Tables). All you must know to follow this tutorial is how to read the content of a file whatever the programming language you are using.
Now, let's talk about what we can find in a LUT file. It can contain tones of data but in our case, what you will generally find is 256 lines filled each time with 3 values (separated by spaces).
What are these 3 values? Well... It's again the values of our 3 (Red,Green,Blue) pixel components. And why there are exactly 256 lines? These lines correspond to the different intensity levels that a pixel of an image can take. The intensity level of a pixel is a value between 0 and 255 so there are 256 possibilities of values. Let's see how to apply a LUT to an image...

The first thing you have to do is to transform your image in grey level with the method of your choice. You may understand that you can get different results with just one LUT by changing the grey level method that you apply on your image. If you don't know how to transform your image in grey level, I can only suggest you to read my last post where you will find all what you need. What we have to do after this is to replace all pixel components of our grey level image by their corresponding values in the LUT. We won't open a file and read the line corresponding to the intensity level of the current grey pixel for each pixel of our image obviously. The best thing we can do is to load all data of the LUT file in an array of 256 indexes. Each index will contain 3 values: Red, Green, Blue. At the index i (I mean at array.(i)), there will be the (Red,Green,Blue) values retrieved at the line i in the LUT file and corresponding to the color that will replace all pixels of your grey level image that have an intensity level of i. In conclusion, the function which applies a color effect from a LUT to an image may look like that :

As you see, we get the array corresponding to the LUT that we want to apply to our image with the get_lut function, then we browse the image matrix representation, we get the grey level of the current pixel with the get_grey function which returns a (Grey,Grey,Grey) pixel (according to the grey level method we want to use which explains the presence of the parameter style which is just a string variable) and we replace the current pixel by the new (Red,Green,Blue) values located at the index r of the array where r is the grey level value of the Red component of the current pixel (but I could have written array.(g) or array.(b) because the grey level of a pixel verifies Red=Green=Blue).
Now, here is the get_lut function :

Some explanations : Firstly, the integer n determines the name of the LUT file that will be open. Then we create an array of 256 indexes initialized with (0,0,0). It's this same array that will be send to the previous lut function after getting all the data of the LUT file. We have a counter named cpt which will help us to fill the 256 indexes of the array. We open the specified file and while we are not at the end of this file, we get a line in a string variable, we split each line into 3 values which represent a new (Red,Green,Blue) pixel (note that I have a function named split which can put all elements of a string variable in a list, the character used to separate these elements must be specified, plus, the ios function converts a string variable to an integer (ios stands for int_of_string)) and we fill the current index with these 3 values. Finally, at the end of the file, we can close it and send the array to the previous lut function.

Here is the content of the LUT_autumn, LUT_copper, LUT_fire, LUT_jet and LUT_spectrum files and the different results of these effects using at each time the "Averaging" grey level method.
Autumn
255 0 0
255 1 0
255 2 0
255 3 0
255 4 0
255 5 0
255 6 0
255 7 0
255 8 0
255 9 0
255 10 0
255 11 0
255 12 0
255 13 0
255 14 0
255 15 0
255 16 0
255 17 0
255 18 0
255 19 0
255 20 0
255 21 0
255 22 0
255 23 0
255 24 0
255 25 0
255 26 0
255 27 0
255 28 0
255 29 0
255 30 0
255 31 0
255 32 0
255 33 0
255 34 0
255 35 0
255 36 0
255 37 0
255 38 0
255 39 0
255 40 0
255 41 0
255 42 0
255 43 0
255 44 0
255 45 0
255 46 0
255 47 0
255 48 0
255 49 0
255 50 0
255 51 0
255 52 0
255 53 0
255 54 0
255 55 0
255 56 0
255 57 0
255 58 0
255 59 0
255 60 0
255 61 0
255 62 0
255 63 0
255 64 0
255 65 0
255 66 0
255 67 0
255 68 0
255 69 0
255 70 0
255 71 0
255 72 0
255 73 0
255 74 0
255 75 0
255 76 0
255 77 0
255 78 0
255 79 0
255 80 0
255 81 0
255 82 0
255 83 0
255 84 0
255 85 0
255 86 0
255 87 0
255 88 0
255 89 0
255 90 0
255 91 0
255 92 0
255 93 0
255 94 0
255 95 0
255 96 0
255 97 0
255 98 0
255 99 0
255 100 0
255 101 0
255 102 0
255 103 0
255 104 0
255 105 0
255 106 0
255 107 0
255 108 0
255 109 0
255 110 0
255 111 0
255 112 0
255 113 0
255 114 0
255 115 0
255 116 0
255 117 0
255 118 0
255 119 0
255 120 0
255 121 0
255 122 0
255 123 0
255 124 0
255 125 0
255 126 0
255 127 0
255 128 0
255 129 0
255 130 0
255 131 0
255 132 0
255 133 0
255 134 0
255 135 0
255 136 0
255 137 0
255 138 0
255 139 0
255 140 0
255 141 0
255 142 0
255 143 0
255 144 0
255 145 0
255 146 0
255 147 0
255 148 0
255 149 0
255 150 0
255 151 0
255 152 0
255 153 0
255 154 0
255 155 0
255 156 0
255 157 0
255 158 0
255 159 0
255 160 0
255 161 0
255 162 0
255 163 0
255 164 0
255 165 0
255 166 0
255 167 0
255 168 0
255 169 0
255 170 0
255 171 0
255 172 0
255 173 0
255 174 0
255 175 0
255 176 0
255 177 0
255 178 0
255 179 0
255 180 0
255 181 0
255 182 0
255 183 0
255 184 0
255 185 0
255 186 0
255 187 0
255 188 0
255 189 0
255 190 0
255 191 0
255 192 0
255 193 0
255 194 0
255 195 0
255 196 0
255 197 0
255 198 0
255 199 0
255 200 0
255 201 0
255 202 0
255 203 0
255 204 0
255 205 0
255 206 0
255 207 0
255 208 0
255 209 0
255 210 0
255 211 0
255 212 0
255 213 0
255 214 0
255 215 0
255 216 0
255 217 0
255 218 0
255 219 0
255 220 0
255 221 0
255 222 0
255 223 0
255 224 0
255 225 0
255 226 0
255 227 0
255 228 0
255 229 0
255 230 0
255 231 0
255 232 0
255 233 0
255 234 0
255 235 0
255 236 0
255 237 0
255 238 0
255 239 0
255 240 0
255 241 0
255 242 0
255 243 0
255 244 0
255 245 0
255 246 0
255 247 0
255 248 0
255 249 0
255 250 0
255 251 0
255 252 0
255 253 0
255 254 0
255 255 0
Copper
0 0 0
1 1 0
3 2 1
4 2 1
5 3 2
6 4 2
8 5 3
9 5 3
10 6 4
11 7 4
13 8 5
14 9 5
15 9 6
16 10 6
18 11 7
19 12 7
20 12 8
21 13 8
22 14 9
24 15 9
25 16 10
26 16 10
28 17 11
29 18 11
30 19 12
31 20 12
33 20 13
34 21 13
35 22 14
36 23 14
38 23 15
39 24 15
40 25 16
41 26 16
43 27 17
44 27 17
45 28 18
46 29 18
48 30 19
49 30 19
50 31 20
51 32 20
53 33 21
54 34 21
55 34 22
56 35 22
58 36 23
59 37 23
60 37 24
61 38 24
63 39 25
64 40 25
65 41 26
66 41 26
68 42 27
69 43 27
70 44 28
71 45 28
73 45 29
74 46 29
75 47 30
76 48 30
78 48 31
79 49 31
80 50 32
81 51 32
83 52 33
84 52 33
85 53 34
86 54 34
88 55 35
89 55 35
90 56 36
91 57 36
93 58 37
94 59 37
95 59 38
96 60 38
98 61 39
99 62 39
100 62 40
101 63 40
103 64 41
104 65 41
105 66 42
106 66 42
108 67 43
109 68 43
110 69 44
111 70 44
113 70 45
114 71 45
115 72 46
116 73 46
118 73 47
119 74 47
120 75 48
121 76 48
123 77 49
124 77 49
125 78 50
126 79 50
128 80 51
129 80 51
130 81 52
131 82 52
133 83 53
134 84 53
135 84 54
136 85 54
138 86 55
139 87 55
140 87 56
141 88 56
143 89 57
144 90 57
145 91 58
146 91 58
148 92 59
149 93 59
150 94 60
151 95 60
153 95 61
154 96 61
155 97 62
156 98 62
158 98 63
159 99 63
160 100 64
161 101 64
163 102 65
164 102 65
165 103 66
166 104 66
168 105 67
169 105 67
170 106 68
171 107 68
172 108 69
174 109 69
175 109 70
176 110 70
178 111 71
179 112 71
180 112 72
181 113 72
182 114 73
184 115 73
185 116 74
186 116 74
188 117 75
189 118 75
190 119 76
191 120 76
193 120 77
194 121 77
195 122 78
196 123 78
198 123 79
199 124 79
200 125 80
201 126 80
203 127 81
204 127 81
205 128 82
206 129 82
208 130 83
209 130 83
210 131 84
211 132 84
212 133 85
214 134 85
215 134 86
216 135 86
218 136 87
219 137 87
220 137 88
221 138 88
223 139 89
224 140 89
225 141 90
226 141 90
228 142 91
229 143 91
230 144 92
231 145 92
233 145 93
234 146 93
235 147 94
236 148 94
238 148 95
239 149 95
240 150 96
241 151 96
243 152 97
244 152 97
245 153 98
246 154 98
248 155 99
249 155 99
250 156 100
251 157 100
252 158 100
254 159 101
255 159 101
255 160 102
255 161 102
255 162 103
255 162 103
255 163 104
255 164 104
255 165 105
255 166 105
255 166 106
255 167 106
255 168 107
255 169 107
255 170 108
255 170 108
255 171 109
255 172 109
255 173 110
255 173 110
255 174 111
255 175 111
255 176 112
255 177 112
255 177 113
255 178 113
255 179 114
255 180 114
255 180 115
255 181 115
255 182 116
255 183 116
255 184 117
255 184 117
255 185 118
255 186 118
255 187 119
255 187 119
255 188 120
255 189 120
255 190 121
255 191 121
255 191 122
255 192 122
255 193 123
255 194 123
255 195 124
255 195 124
255 196 125
255 197 125
255 198 126
255 198 126
255 199 127 
Fire
0 0 0
0 0 7
0 0 15
0 0 22
0 0 30
0 0 38
0 0 45
0 0 53
0 0 61
0 0 65
0 0 69
0 0 74
0 0 78
0 0 82
0 0 87
0 0 91
1 0 96
4 0 100
7 0 104
10 0 108
13 0 113
16 0 117
19 0 121
22 0 125
25 0 130
28 0 134
31 0 138
34 0 143
37 0 147
40 0 151
43 0 156
46 0 160
49 0 165
52 0 168
55 0 171
58 0 175
61 0 178
64 0 181
67 0 185
70 0 188
73 0 192
76 0 195
79 0 199
82 0 202
85 0 206
88 0 209
91 0 213
94 0 216
98 0 220
101 0 220
104 0 221
107 0 222
110 0 223
113 0 224
116 0 225
119 0 226
122 0 227
125 0 224
128 0 222
131 0 220
134 0 218
137 0 216
140 0 214
143 0 212
146 0 210
148 0 206
150 0 202
152 0 199
154 0 195
156 0 191
158 0 188
160 0 184
162 0 181
163 0 177
164 0 173
166 0 169
167 0 166
168 0 162
170 0 158
171 0 154
173 0 151
174 0 147
175 0 143
177 0 140
178 0 136
179 0 132
181 0 129
182 0 125
184 0 122
185 0 118
186 0 114
188 0 111
189 0 107
190 0 103
192 0 100
193 0 96
195 0 93
196 1 89
198 3 85
199 5 82
201 7 78
202 8 74
204 10 71
205 12 67
207 14 64
208 16 60
209 19 56
210 21 53
212 24 49
213 27 45
214 29 42
215 32 38
217 35 35
218 37 31
220 40 27
221 43 23
223 46 20
224 48 16
226 51 12
227 54 8
229 57 5
230 59 4
231 62 3
233 65 3
234 68 2
235 70 1
237 73 1
238 76 0
240 79 0
241 81 0
243 84 0
244 87 0
246 90 0
247 92 0
249 95 0
250 98 0
252 101 0
252 103 0
252 105 0
253 107 0
253 109 0
253 111 0
254 113 0
254 115 0
255 117 0
255 119 0
255 121 0
255 123 0
255 125 0
255 127 0
255 129 0
255 131 0
255 133 0
255 134 0
255 136 0
255 138 0
255 140 0
255 141 0
255 143 0
255 145 0
255 147 0
255 148 0
255 150 0
255 152 0
255 154 0
255 155 0
255 157 0
255 159 0
255 161 0
255 162 0
255 164 0
255 166 0
255 168 0
255 169 0
255 171 0
255 173 0
255 175 0
255 176 0
255 178 0
255 180 0
255 182 0
255 184 0
255 186 0
255 188 0
255 190 0
255 191 0
255 193 0
255 195 0
255 197 0
255 199 0
255 201 0
255 203 0
255 205 0
255 206 0
255 208 0
255 210 0
255 212 0
255 213 0
255 215 0
255 217 0
255 219 0
255 220 0
255 222 0
255 224 0
255 226 0
255 228 0
255 230 0
255 232 0
255 234 0
255 235 4
255 237 8
255 239 13
255 241 17
255 242 21
255 244 26
255 246 30
255 248 35
255 248 42
255 249 50
255 250 58
255 251 66
255 252 74
255 253 82
255 254 90
255 255 98
255 255 105
255 255 113
255 255 121
255 255 129
255 255 136
255 255 144
255 255 152
255 255 160
255 255 167
255 255 175
255 255 183
255 255 191
255 255 199
255 255 207
255 255 215
255 255 223
255 255 227
255 255 231
255 255 235
255 255 239
255 255 243
255 255 247
255 255 251
255 255 255
255 255 255
255 255 255
255 255 255
255 255 255
255 255 255
255 255 255
255 255 255 
Jet
0 0 131
0 0 135
0 0 139
0 0 143
0 0 147
0 0 151
0 0 155
0 0 159
0 0 163
0 0 167
0 0 171
0 0 175
0 0 179
0 0 183
0 0 187
0 0 191
0 0 195
0 0 199
0 0 203
0 0 207
0 0 211
0 0 215
0 0 219
0 0 223
0 0 227
0 0 231
0 0 235
0 0 239
0 0 243
0 0 247
0 0 251
0 0 255
0 4 255
0 8 255
0 12 255
0 16 255
0 20 255
0 24 255
0 28 255
0 32 255
0 36 255
0 40 255
0 44 255
0 48 255
0 52 255
0 56 255
0 60 255
0 64 255
0 68 255
0 72 255
0 76 255
0 80 255
0 84 255
0 88 255
0 92 255
0 96 255
0 100 255
0 104 255
0 108 255
0 112 255
0 116 255
0 120 255
0 124 255
0 128 255
0 131 255
0 135 255
0 139 255
0 143 255
0 147 255
0 151 255
0 155 255
0 159 255
0 163 255
0 167 255
0 171 255
0 175 255
0 179 255
0 183 255
0 187 255
0 191 255
0 195 255
0 199 255
0 203 255
0 207 255
0 211 255
0 215 255
0 219 255
0 223 255
0 227 255
0 231 255
0 235 255
0 239 255
0 243 255
0 247 255
0 251 255
0 255 255
4 255 251
8 255 247
12 255 243
16 255 239
20 255 235
24 255 231
28 255 227
32 255 223
36 255 219
40 255 215
44 255 211
48 255 207
52 255 203
56 255 199
60 255 195
64 255 191
68 255 187
72 255 183
76 255 179
80 255 175
84 255 171
88 255 167
92 255 163
96 255 159
100 255 155
104 255 151
108 255 147
112 255 143
116 255 139
120 255 135
124 255 131
128 255 128
131 255 124
135 255 120
139 255 116
143 255 112
147 255 108
151 255 104
155 255 100
159 255 96
163 255 92
167 255 88
171 255 84
175 255 80
179 255 76
183 255 72
187 255 68
191 255 64
195 255 60
199 255 56
203 255 52
207 255 48
211 255 44
215 255 40
219 255 36
223 255 32
227 255 28
231 255 24
235 255 20
239 255 16
243 255 12
247 255 8
251 255 4
255 255 0
255 251 0
255 247 0
255 243 0
255 239 0
255 235 0
255 231 0
255 227 0
255 223 0
255 219 0
255 215 0
255 211 0
255 207 0
255 203 0
255 199 0
255 195 0
255 191 0
255 187 0
255 183 0
255 179 0
255 175 0
255 171 0
255 167 0
255 163 0
255 159 0
255 155 0
255 151 0
255 147 0
255 143 0
255 139 0
255 135 0
255 131 0
255 128 0
255 124 0
255 120 0
255 116 0
255 112 0
255 108 0
255 104 0
255 100 0
255 96 0
255 92 0
255 88 0
255 84 0
255 80 0
255 76 0
255 72 0
255 68 0
255 64 0
255 60 0
255 56 0
255 52 0
255 48 0
255 44 0
255 40 0
255 36 0
255 32 0
255 28 0
255 24 0
255 20 0
255 16 0
255 12 0
255 8 0
255 4 0
255 0 0
251 0 0
247 0 0
243 0 0
239 0 0
235 0 0
231 0 0
227 0 0
223 0 0
219 0 0
215 0 0
211 0 0
207 0 0
203 0 0
199 0 0
195 0 0
191 0 0
187 0 0
183 0 0
179 0 0
175 0 0
171 0 0
167 0 0
163 0 0
159 0 0
155 0 0
151 0 0
147 0 0
143 0 0
139 0 0
135 0 0
131 0 0
128 0 0
Spectrum
255 0 0
255 6 0
255 12 0
255 18 0
255 24 0
255 30 0
255 36 0
255 42 0
255 48 0
255 54 0
255 60 0
255 66 0
255 72 0
255 78 0
255 84 0
255 90 0
255 96 0
255 102 0
255 108 0
255 114 0
255 120 0
255 126 0
255 132 0
255 138 0
255 144 0
255 150 0
255 156 0
255 162 0
255 168 0
255 174 0
255 180 0
255 186 0
255 192 0
255 198 0
255 204 0
255 210 0
255 216 0
255 222 0
255 228 0
255 234 0
255 240 0
255 246 0
255 252 0
252 255 0
246 255 0
240 255 0
234 255 0
228 255 0
222 255 0
216 255 0
210 255 0
204 255 0
198 255 0
192 255 0
186 255 0
180 255 0
174 255 0
168 255 0
162 255 0
156 255 0
150 255 0
144 255 0
138 255 0
132 255 0
126 255 0
120 255 0
114 255 0
108 255 0
102 255 0
96 255 0
90 255 0
84 255 0
78 255 0
72 255 0
66 255 0
60 255 0
54 255 0
48 255 0
42 255 0
36 255 0
30 255 0
24 255 0
18 255 0
12 255 0
6 255 0
0 255 0
0 255 6
0 255 12
0 255 18
0 255 24
0 255 30
0 255 36
0 255 42
0 255 48
0 255 54
0 255 60
0 255 66
0 255 72
0 255 78
0 255 84
0 255 90
0 255 96
0 255 102
0 255 108
0 255 114
0 255 120
0 255 126
0 255 132
0 255 138
0 255 144
0 255 150
0 255 156
0 255 162
0 255 168
0 255 174
0 255 180
0 255 186
0 255 192
0 255 198
0 255 204
0 255 210
0 255 216
0 255 222
0 255 228
0 255 234
0 255 240
0 255 246
0 255 252
0 252 255
0 246 255
0 240 255
0 234 255
0 228 255
0 222 255
0 216 255
0 210 255
0 204 255
0 198 255
0 192 255
0 186 255
0 180 255
0 174 255
0 168 255
0 162 255
0 156 255
0 150 255
0 144 255
0 138 255
0 132 255
0 126 255
0 120 255
0 114 255
0 108 255
0 102 255
0 96 255
0 90 255
0 84 255
0 78 255
0 72 255
0 66 255
0 60 255
0 54 255
0 48 255
0 42 255
0 36 255
0 30 255
0 24 255
0 18 255
0 12 255
0 6 255
0 0 255
6 0 255
12 0 255
18 0 255
24 0 255
30 0 255
36 0 255
42 0 255
48 0 255
54 0 255
60 0 255
66 0 255
72 0 255
78 0 255
84 0 255
90 0 255
96 0 255
102 0 255
108 0 255
114 0 255
120 0 255
126 0 255
132 0 255
138 0 255
144 0 255
150 0 255
156 0 255
162 0 255
168 0 255
174 0 255
180 0 255
186 0 255
192 0 255
198 0 255
204 0 255
210 0 255
216 0 255
222 0 255
228 0 255
234 0 255
240 0 255
246 0 255
252 0 255
255 0 252
255 0 246
255 0 240
255 0 234
255 0 228
255 0 222
255 0 216
255 0 210
255 0 204
255 0 198
255 0 192
255 0 186
255 0 180
255 0 174
255 0 168
255 0 162
255 0 156
255 0 150
255 0 144
255 0 138
255 0 132
255 0 126
255 0 120
255 0 114
255 0 108
255 0 102
255 0 96
255 0 90
255 0 84
255 0 78
255 0 72
255 0 66
255 0 60
255 0 54
255 0 48
255 0 42
255 0 36
255 0 30
255 0 24
255 0 18
255 0 12
255 0 6
255 0 0


Download the files there...

Tuesday, May 6, 2014

The Classic Filters

As I said it in my last post, we are going to see how to implement some image processing filters, starting with the classic ones. Note that I will certainly use some useful functions that were previously described. So if you didn't read my last post, I recommend you to do it (don't worry, it's not very long).
And before beginning, I would like to show you something...
As you may know now, the image processing is all about matrices but I didn't show you how to convert your image into a matrix in order to work on it and then transform this matrix into your new image. The answer is that it just depends on the image management library you are using. For example, I use OCamlSDL to see the results of my functions (because as I already said, I will use the OCaml programming language). So as you can imagine, I have a function that loads an image, another one which transforms this image to a matrix, another one which does the reverse and finally a function which can save the resulting image as a .bmp file :

So let's begin with the most simple filter, the negative filter. What you have to do is replacing all the (Red,Green,Blue) pixels of your image by (255 Red255 Green255 Blue).

Note that you can also try to see what's happening when you apply the negative effect only on some pixel channels of your choice. Here is my result :
Now, we will have to do conversions between floating point numbers and integers with the sepia filter. As it's also a very simple filter, I show you directly the formula I used in an example of source code :

Easy?! Just note that the fix_rgb function was already described in my last post, foi is a function that converts an integer to a floating point number (foi stands for float_of_int), iof converts a floating point number to an integer (iof stands for int_of_float) and I put dots behind all operators like that "+." just because it's the OCaml syntax when you are manipulating floating point numbers. The beautiful result :
The next function that I am going present can provide many different results.
In fact, we will enabled and disabled some pixel channels in order to colorize our image.
So if you want to colorize your image in Magenta for example, you have to browse your image matrix representation and replace all Green pixel channels by 0. Why we don't do same for the Red or the Blue pixel components? Because Red+Blue=Magenta, so we don't change their current value!
You can now try all possibilities which are normally those ones (we will ignore the cases (0,0,0) and (255,255,255) that we already saw in my last post) :
What you can also do and which is more interesting, is to observe what's happening when you shift or swap the pixel components. Actually, it will give you lots of new color effects and they are too many for giving you the complete list of possibilities... (Red,Blue,Green), (Green,Blue,Red), (Green,Red,Blue), (Blue,Red,Green), (Blue,Green,Red), (Red,Red,Green), ...
You still can disable some pixel components like (Green,0,Red), (Blue,0,Green), ...
It's time to talk about the grey level of an image. It exists many methods to convert your image in grey level and I will try to present the most important ones. Firstly, you must know that the particularity of the grey level is that it always verifies that the RedGreen and Blue pixel components in any pixel of your image become equal. You can use the "Averaging" method where all (Red,Green,Blue) pixels of your image must be replaced by (Grey,Grey,Grey) where Grey = (Red+Green+Blue) / 3.
Then comes the "Luma" method where Grey Red * 0.2126 + Green * 0.7152 + Blue * 0.0722
(here again, some conversions between integers and floating point numbers will be necessary).
You can also convert an image to the grey level with the RedGreen or Blue channels by considering (Grey,Grey,Grey) as (Red,Red,Red) for the Red channel
or as (Green,Green,Green) or (Blue,Blue,Blue).
You can use the "Max decomposition" method where Grey = max(Red,Green,Blue)
or the "Min decomposition" method where Grey = min(Red,Green,Blue)
and finally there is the "Desaturation" method where
Grey = (max(Red,Green,Blue) + min(Red,Green,Blue)) / 2. Here is the "Averaging" result :
Now, I suggest to change your image to another color space like the famous YCbCr one.
This function is based on conversions like the sepia filter and you can get this type of effect :
Here is how I wrote my converting function to the YCbCr color space according to Wikipedia :

Well, we will finish this post with a last filter which can solarize your image.
This function will only depend on a certain threshold which must be between 0 and 255.
You will have to browse your matrix and apply this procedure for every components of every pixels :

As you see, the pixel components are replaced by their negative value only if their current value is under the threshold you have chosen. Start to test your function with a threshold of 127 for example.
Here is my result :

Friday, May 2, 2014

Let's Go!

Dear reader from somewhere, as you have probably seen, this blog will talk about the image processing mechanisms. Firstly, you must understand that we obviously won't see all things that exist in this field because it's just impossible but what you will see will help you to understand better how famous image editing software work (like GIMP or Adobe Photoshop). I mean how  the hell  can they transform an image into another one just by playing with pixels. So here we are, what is a pixel?
I'm talking about this little, very little element that comprises your digital image. This pixel is itself composed of data. These data are the colors of the famous (Alpha,Red,Green,Blue) or ARGB color model. Now if we see these 3 last colors as spotlights, we easily understand that we can generate new colors by turning them on and off. Here is an illustration where we see that Blue+Red=Magenta, Green+Red=Yellow, Green+Blue=Cyan, ... It's what we call additive color.
In computer science, these same data are represented with just 1 unsigned integer of 32bits.
Each ARGcomponent is consequently coded on 32bits / 4 colors = 8bits.
Even if Alpha isn't really a color. It's just an information which determines the opacity of your image.
If we "ignore" the Alpha information and consider only RGB, the lower value of these 3 colors will be
3 * 00000000 (= (0,0,0) = Black) and the higher value will be 3 * 11111111 (= (255,255,255) = White). In the  ARG RGcolor model, the representation of the pure Green color, for example, on 3*8bits, is 00000000 11111111 00000000 (= (0,255,0)) where the first 8bits indicate that the Red channel is totally disabled, like the last 8bits representing the state of the Blue channel and the second 8bits indicate that the Green channel is enabled and in addition to that, it's at its maximum value. Now you can imagine what is the binary representation of an image with a width w and a height h,
it's w * h pixels composed of 3*8bits (or even more as we "ignore" the Alpha information here).
All of this lead us to the matrices which are two dimensional arrays where we can find at each location (x,y) (= (column,row)) our 3 RGB colors. And each time, we will have to fully or partially read these matrices in order to update every colors according to what we want to do on our image. Apart from that, I hope you will enjoy what you will learn in my future posts and maybe it will encourage you to develop your own image editing software, I will be glad to use it if you link it to me. Here is an interesting image editing software that I recently found : PhotoDemon.



Note that certain of my future posts will be accompanied of source code examples.
And I've decided to use the OCaml programming language, and not Camel (ʘ‿ʘ)
Look at its very understandable syntax :

You can easily do lots of things with OCaml... Moreover, in my add function, I didn't had to specify the type of the variables x and y, the language automatically detects that in this case, the parameters are integers, like the resulting value, because of the presence of the operator "+". Let's test this function :

×
-
+
terminal

Objective Caml version 4.12.0

# add(21, 21);;
- : int = 42

Now, here are some others functions that will be useful to get the value of one pixel component or to make sure that a pixel component value is strictly between 0 and 255 as we just saw it.

Finally, here is an example on how to browse a matrix where matrix.(i).(j) is the location of the current (Red,Green,Blue) pixel and the symbol "<-" means receive. Plus, the location of the first pixel in a matrix is (0,0) (at the top-left corner) and not (1,1) as we could imagine. So if the dimensions of an image are widthxheight, the last pixel (at the bottom-right corner because we browse the matrix left to right and top to bottom) is at location (width-1,height-1) (and not at (width,height)).

But you can use the programming language of your choice...
Next time, I will present some classic image processing filters.