Skip to content

Commit ff39bab

Browse files
committed
1.0: init version
0 parents  commit ff39bab

File tree

7 files changed

+531
-0
lines changed

7 files changed

+531
-0
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "src/stb"]
2+
path = src/stb
3+
url = https://github.com/nothings/stb

LICENSE

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <https://unlicense.org>

Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
PNAME = stbibalance
2+
CFLAGS = -std=c99 -O2 -Wall -Wextra -Wno-unused-but-set-variable -Wno-unused-parameter -Werror
3+
LDLIBS = -lm -s
4+
SRCS = src/balance.c
5+
6+
all: $(PNAME)
7+
8+
$(PNAME): $(SRCS)
9+
$(CC) $(CFLAGS) $^ $(LDLIBS) -o $@
10+
11+
clean:
12+
rm -f $(PNAME)

README.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# stbibalance
2+
3+
Balance filter based of Gauss blur.
4+
Used:
5+
* Gauss blur: [iir_gauss_blur](https://github.com/arkanis/iir_gauss_blur).
6+
* STB: [stb](https://github.com/nothings/stb).
7+
8+
Balance is a thin filter (unlike others that use a thick difference between
9+
the original image and its blurred version) that uses the difference between
10+
a single and double radius blurred version of the original image
11+
(single and double `sigma`).
12+
This difference is used not directly, but by applying an `overlay` four times,
13+
with the colors inverted.
14+
15+
This filter was first applied in [STEX](https://github.com/ImageProcessing-ElectronicPublications/scantailor-experimental) (2024)
16+
in a single-component version (Y, the values of the color components were aligned
17+
in accordance with the brightness values before and after the filter).
18+
19+
Here this filter is implemented in a full-color version.
20+
21+
## Usage
22+
23+
`./stbibalance [-h] [-s sigma] [-m mixed] input-file output-file`
24+
25+
`-s sigma` The sigma of the gauss normal distribution (number >= 0.5).
26+
Larger values result in a stronger blur.
27+
28+
`-m mixed` The mixed coefficient.
29+
30+
`-h` display this help and exit.
31+
32+
You can use either sigma to specify the strengh of the blur.
33+
34+
The performance is independent of the blur strengh (sigma). This tool is an
35+
implementation of the paper "Recursive implementaion of the Gaussian filter"
36+
by Ian T. Young and Lucas J. van Vliet.
37+
38+
stb_image and stb_image_write by Sean Barrett and others is used to read and
39+
write images.
40+
41+
## Installation
42+
43+
- Clone the repo or download the source `git clone --recurse-submodules https://github.com/ImageProcessing-ElectronicPublications/stbibalance`
44+
- Execute `make`
45+
- Done. Either use the `stbibalance` executable directly or copy it somewhere in your PATH.
46+
47+
## Links
48+
49+
* STB: [stb](https://github.com/nothings/stb).
50+
* Gauss blur: [iir_gauss_blur](https://github.com/arkanis/iir_gauss_blur).
51+
* Examples: [stbibalance-examples](https://github.com/ImageProcessing-ElectronicPublications/stbibalance-examples).

src/balance.c

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
#define _GNU_SOURCE
2+
#include <stdio.h>
3+
#include <unistd.h>
4+
5+
#define STB_IMAGE_IMPLEMENTATION
6+
#define STBI_FAILURE_USERMSG
7+
#include "stb/stb_image.h"
8+
#define STB_IMAGE_WRITE_IMPLEMENTATION
9+
#include "stb/stb_image_write.h"
10+
#define IIR_GAUSS_BLUR_IMPLEMENTATION
11+
#include "iir_gauss_blur.h"
12+
13+
void usage(char* progname)
14+
{
15+
fprintf(stderr,
16+
"%s %s %s\n",
17+
"Usage:", progname, "[-h] [-s sigma] [-m mixed] input-file output.png\n"
18+
"Balance filter an image and save it as PNG.\n"
19+
);
20+
}
21+
22+
void help(float sigma, float mix)
23+
{
24+
fprintf(stderr,
25+
"%s %f %s %f %s\n",
26+
" -s sigma The sigma of the gauss normal distribution (number >= 0.5, default =", sigma, ").\n"
27+
" Larger values result in a stronger blur.\n"
28+
" -m mixed The mixed coefficient (number, default =", mix, ").\n"
29+
" -h display this help and exit.\n"
30+
"\n"
31+
"You can use either sigma to specify the strengh of the blur.\n"
32+
"\n"
33+
"The performance is independent of the blur strengh (sigma). This tool is an\n"
34+
"implementation of the paper \"Recursive implementaion of the Gaussian filter\"\n"
35+
"by Ian T. Young and Lucas J. van Vliet.\n"
36+
"\n"
37+
"stb_image and stb_image_write by Sean Barrett and others is used to read and\n"
38+
"write images.\n"
39+
);
40+
}
41+
42+
uint8_t* image_copy(unsigned int width, unsigned int height, unsigned char components, unsigned char* image)
43+
{
44+
size_t image_size = height * width * components;
45+
uint8_t* dest = (unsigned char*)malloc(image_size * sizeof(unsigned char));
46+
if (dest != NULL)
47+
{
48+
for (size_t i = 0; i < image_size; i++)
49+
{
50+
dest[i] = image[i];
51+
}
52+
}
53+
return dest;
54+
}
55+
56+
void image_overlay_blur(unsigned int width, unsigned int height, unsigned char components, unsigned char* blur1r, unsigned char* blur2r)
57+
{
58+
size_t image_size = height * width * components;
59+
if ((blur1r != NULL) && (blur2r != NULL))
60+
{
61+
for (size_t i = 0; i < image_size; i++)
62+
{
63+
float b1r = blur1r[i];
64+
float b2r = blur2r[i];
65+
66+
/* overlay 1 */
67+
float base = 255.0f - b1r;
68+
float overlay = b2r;
69+
float retval1 = base;
70+
if (base > 127.5f)
71+
{
72+
retval1 = 255.0f - retval1;
73+
overlay = 255.0f - overlay;
74+
}
75+
retval1 *= overlay;
76+
retval1 += retval1;
77+
retval1 /= 255.0f;
78+
if (base > 127.5f)
79+
{
80+
retval1 = 255.0f - retval1;
81+
}
82+
83+
/* overlay 2 */
84+
base = 255.0f - b2r;
85+
overlay = b1r;
86+
float retval2 = base;
87+
if (base > 127.5f)
88+
{
89+
retval2 = 255.0f - retval2;
90+
overlay = 255.0f - overlay;
91+
}
92+
retval2 *= overlay;
93+
retval2 += retval2;
94+
retval2 /= 255.0f;
95+
if (base > 127.5f)
96+
{
97+
retval2 = 255.0f - retval2;
98+
}
99+
100+
blur1r[i] = (retval1 < 0.0f) ? 0 : ((retval1 < 255.0f) ? (uint8_t)(retval1 + 0.5f) : 255);
101+
blur2r[i] = (retval2 < 0.0f) ? 0 : ((retval2 < 255.0f) ? (uint8_t)(retval2 + 0.5f) : 255);
102+
}
103+
}
104+
}
105+
106+
void image_overlay(unsigned int width, unsigned int height, unsigned char components, unsigned char* image, unsigned char* blur)
107+
{
108+
size_t image_size = height * width * components;
109+
if ((image != NULL) && (blur != NULL))
110+
{
111+
for (size_t i = 0; i < image_size; i++)
112+
{
113+
float im = image[i];
114+
float bl = blur[i];
115+
116+
/* overlay*/
117+
float base = im;
118+
float overlay = bl;
119+
float retval = base;
120+
if (base > 127.5f)
121+
{
122+
retval = 255.0f - retval;
123+
overlay = 255.0f - overlay;
124+
}
125+
retval *= overlay;
126+
retval += retval;
127+
retval /= 255.0f;
128+
if (base > 127.5f)
129+
{
130+
retval = 255.0f - retval;
131+
}
132+
133+
blur[i] = (retval < 0.0f) ? 0 : ((retval < 255.0f) ? (uint8_t)(retval + 0.5f) : 255);
134+
}
135+
}
136+
}
137+
138+
void image_mix(unsigned int width, unsigned int height, unsigned char components, float coef, unsigned char* image1, unsigned char* image2)
139+
{
140+
size_t image_size = height * width * components;
141+
if ((image1 != NULL) && (image2 != NULL))
142+
{
143+
for (size_t i = 0; i < image_size; i++)
144+
{
145+
float im1 = image1[i];
146+
float im2 = image2[i];
147+
148+
/* overlay*/
149+
float retval = coef * im1 + (1.0 - coef) * im2;
150+
151+
image2[i] = (retval < 0.0f) ? 0 : ((retval < 255.0f) ? (uint8_t)(retval + 0.5f) : 255);
152+
}
153+
}
154+
}
155+
156+
int main(int argc, char** argv)
157+
{
158+
float sigma = 10.0f;
159+
float mix = 1.0f;
160+
161+
int opt;
162+
while ( (opt = getopt(argc, argv, "s:m:h")) != -1 )
163+
{
164+
switch(opt)
165+
{
166+
case 's':
167+
sigma = strtof(optarg, NULL);
168+
break;
169+
case 'm':
170+
mix = strtof(optarg, NULL);
171+
break;
172+
case 'h':
173+
usage(argv[0]);
174+
help(sigma, mix);
175+
return 0;
176+
default:
177+
usage(argv[0]);
178+
return 1;
179+
}
180+
}
181+
182+
// Need at least two filenames after the last option
183+
if (argc < optind + 2)
184+
{
185+
usage(argv[0]);
186+
return 1;
187+
}
188+
189+
int width = 0, height = 0, components = 1;
190+
uint8_t* image = stbi_load(argv[optind], &width, &height, &components, 0);
191+
if (image == NULL)
192+
{
193+
fprintf(stderr, "Failed to load %s: %s.\n", argv[optind], stbi_failure_reason());
194+
return 2;
195+
}
196+
197+
uint8_t* blur1r = image_copy(width, height, components, image);
198+
if (blur1r == NULL)
199+
{
200+
fprintf(stderr, "ERROR: not use memmory\n");
201+
return 3;
202+
}
203+
204+
uint8_t* blur2r = image_copy(width, height, components, image);
205+
if (blur2r == NULL)
206+
{
207+
fprintf(stderr, "ERROR: not use memmory\n");
208+
return 3;
209+
}
210+
211+
iir_gauss_blur(width, height, components, blur1r, sigma);
212+
iir_gauss_blur(width, height, components, blur2r, (sigma + sigma));
213+
214+
image_overlay_blur(width, height, components, blur1r, blur2r);
215+
image_overlay(width, height, components, image, blur1r);
216+
image_overlay(width, height, components, blur1r, blur2r);
217+
image_mix(width, height, components, mix, blur2r, image);
218+
219+
if ( stbi_write_png(argv[optind+1], width, height, components, image, 0) == 0 )
220+
{
221+
fprintf(stderr, "Failed to save %s.\n", argv[optind+1]);
222+
return 4;
223+
}
224+
225+
return 0;
226+
}

0 commit comments

Comments
 (0)