From 118ab671cf7dd9f59f624cae7ac00e7d0c9ce8da Mon Sep 17 00:00:00 2001 From: zvezdochiot Date: Sun, 2 May 2021 09:55:06 +0300 Subject: [PATCH] 0.20210502: BiCubic interpolation and margin --- BUILD | 4 +- CHANGELOG | 4 ++ Makefile | 9 ++- README.md | 3 +- VERSION | 2 +- man/man1/geoconformimage.1 | 5 +- src/geoconform.c | 124 +++++++++++++++++++++++++------------ src/geoconform.h | 5 +- src/geoconformimage.cpp | 9 ++- 9 files changed, 114 insertions(+), 51 deletions(-) diff --git a/BUILD b/BUILD index 1ff2803..9bc1a2d 100644 --- a/BUILD +++ b/BUILD @@ -1,5 +1,5 @@ # GeoConformImage -# 0.20210323 +# 0.20210502 Download -------- @@ -14,6 +14,8 @@ Depends this library: freeimage +For Windows: copy `FreeImage.dll` in project and `FreeImage.lib` + `FreeImage.h` in `src` project. + Build ----- diff --git a/CHANGELOG b/CHANGELOG index 454399d..10fdd8a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,10 @@ ---------------------------------------------------------------- +0.20210502 + + Stable: BiCubic interpolation and margin + 0.20210414 FreeImage: fix ImthresholdGenericLoader diff --git a/Makefile b/Makefile index d328e8d..e238f56 100644 --- a/Makefile +++ b/Makefile @@ -3,25 +3,24 @@ PROGNAME = $(PNAME) CC = gcc CPP = g++ CFLAGS = -Isrc -DUNIX -O2 -Wall -s +SRCS = src VER = 0 -VERB = 20210414 +VERB = 20210502 ifeq ($(OS),Windows_NT) -LIBS = FreeImage.lib +LIBS = $(SRCS)/FreeImage.lib PLIBF = $(PNAME).$(VER).dll PLIBFI = $(PNAME)freeimage.$(VER).dll -RM = del /Q else LIBS = -lfreeimage PLIBF = lib$(PNAME).so.$(VER) PLIBFI = lib$(PNAME)freeimage.so.$(VER) -RM = rm -f endif PLIB = $(PLIBF) $(PLIBFI) PREFIX = /usr/local DOCPREFIX = $(PREFIX)/share/doc/$(PNAME) -SRCS = src INSTALL = install LN = ln -fs +RM = rm -f .PHONY: all clean install diff --git a/README.md b/README.md index 9167317..28ca336 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ geoconformimage [options] ```sh -i N iteration set (default = 10) + -m N margin (default = 0) -p str string conform params: "A0,B0,A1,B1,[...,A9,B9]" -r str string region image: "Xws,Yws,Xne,Yne" -h this help @@ -57,7 +58,7 @@ Output= world-rus.jpg.out.png ## Copyright -Public Domain Mark 1.0 +Public Domain Mark 1.0 No Copyright diff --git a/VERSION b/VERSION index 57a071e..0cb9512 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20210414 +0.20210502 diff --git a/man/man1/geoconformimage.1 b/man/man1/geoconformimage.1 index e8c33eb..cfe1295 100644 --- a/man/man1/geoconformimage.1 +++ b/man/man1/geoconformimage.1 @@ -1,4 +1,4 @@ -.TH "GeoConformImage" 1 0.20210325 "25 Mar 2021" "User Manual" +.TH "GeoConformImage" 1 0.20210502 "2 May 2021" "User Manual" .SH NAME geoconformimage @@ -14,6 +14,9 @@ geoconformimage [options] -i N iteration set (default = 10) .TP +-m N +margin (default = 0) +.TP -p str string conform params: "A0,B0,A1,B1,[...,A9,B9]" .TP diff --git a/src/geoconform.c b/src/geoconform.c index 0b420fa..98192fe 100644 --- a/src/geoconform.c +++ b/src/geoconform.c @@ -55,7 +55,7 @@ IMTpixel IMTcalcS (IMTpixel im) unsigned ims, d; ims = 0; - for (d = 0; d < 3; d++) + for (d = 0; d < COUNTC; d++) { ims += (unsigned)im.c[d]; } @@ -81,8 +81,8 @@ IMTimage IMTalloc (IMTsize size, int bs) } im.size.height = size.height; im.size.width = size.width; - im.bits += 24; - bs -= 24; + im.bits += COUNTC * 8; + bs -= COUNTC * 8; } if (bs > 0) { @@ -112,7 +112,7 @@ IMTimage IMTfree (IMTimage im) free(im.p[y]); } free(im.p); - im.bits -= 24; + im.bits -= COUNTC * 8; } if (im.bits > 0) { @@ -129,46 +129,82 @@ IMTimage IMTfree (IMTimage im) //////////////////////////////////////////////////////////////////////////////// -IMTpixel IMTinterpolation (IMTimage p_im, GCIcoord p) +IMTpixel IMTInterpolateBiCubic (IMTimage p_im, GCIcoord p) { - unsigned d, y1, x1, y2, x2; - float p11, p21, p12, p22, ky, kx, k11, k21, k12, k22, t; + int i, d, xi, yi, xf, yf; + float d0, d2, d3, a0, a1, a2, a3; + float x, y, dx, dy; + float Cc, C[4]; IMTpixel res; - y1 = IndexClamp((int)p.x, (p_im.size.height - 1)); - x1 = IndexClamp((int)p.y, (p_im.size.width - 1)); - y2 = IndexClamp((int)(y1 + 1), (p_im.size.height - 1)); - x2 = IndexClamp((int)(x1 + 1), (p_im.size.width - 1)); - ky = p.x - y1; - if (ky < 0) + y = p.x; + x = p.y; + yi = IndexClamp((int)y, (p_im.size.height - 1)); + xi = IndexClamp((int)x, (p_im.size.width - 1)); + dy = y - yi; + dx = x - xi; + for(d = 0; d < COUNTC; d++) { - ky = 0.0; - } - if (ky > 1) - { - ky = 1.0; - } - kx = p.y - x1; - if (kx < 0) - { - kx = 0.0; - } - if (kx > 1) - { - kx = 1.0; + for(i = -1; i < 3; i++) + { + yf = IndexClamp((int)(y + i), (p_im.size.height - 1)); + xf = IndexClamp((int)x, (p_im.size.width - 1)); + a0 = p_im.p[yf][xf].c[d]; + xf = IndexClamp((int)(x - 1), (p_im.size.width - 1)); + d0 = p_im.p[yf][xf].c[d]; + d0 -= a0; + xf = IndexClamp((int)(x + 1), (p_im.size.width - 1)); + d2 = p_im.p[yf][xf].c[d]; + d2 -= a0; + xf = IndexClamp((int)(x + 2), (p_im.size.width - 1)); + d3 = p_im.p[yf][xf].c[d]; + d3 -= a0; + a1 = -1.0f / 3.0f * d0 + d2 - 1.0f / 6.0f * d3; + a2 = 1.0f / 2.0f * d0 + 1.0f / 2.0f * d2; + a3 = -1.0f / 6.0 * d0 - 1.0f / 2.0f * d2 + 1.0f / 6.0f * d3; + C[i + 1] = a0 + (a1 + (a2 + a3 * dx) * dx) * dx; + } + d0 = C[0] - C[1]; + d2 = C[2] - C[1]; + d3 = C[3] - C[1]; + a0 = C[1]; + a1 = -1.0f / 3.0f * d0 + d2 - 1.0f / 6.0f * d3; + a2 = 1.0f / 2.0f * d0 + 1.0f / 2.0f * d2; + a3 = -1.0f / 6.0f * d0 - 1.0f / 2.0f * d2 + 1.0f / 6.0f * d3; + Cc = a0 + (a1 + (a2 + a3 * dy) * dy) * dy; + res.c[d] = ByteClamp((int)(Cc + 0.5f)); } - k11 = (1.0 - ky) * (1.0 - kx); - k21 = ky * (1.0 - kx); - k12 = (1.0 - ky) * kx; - k22 = ky * kx; - for (d = 0; d < 3; d++) + res = IMTcalcS (res); + + return res; +} + +//////////////////////////////////////////////////////////////////////////////// + +IMTpixel IMTInterpolateBiLine (IMTimage p_im, GCIcoord p) +{ + int d, xi, yi, xf, yf; + float x, y, dx1, dy1, dx2, dy2; + float p11, p12, p21, p22; + IMTpixel res; + + y = p.x; + x = p.y; + yi = IndexClamp((int)y, (p_im.size.height - 1)); + xi = IndexClamp((int)x, (p_im.size.width - 1)); + dy1 = y - yi; + dx1 = x - xi; + dy2 = 1.0f - dy1; + dx2 = 1.0f - dx1; + yf = IndexClamp((int)(y + 1), (p_im.size.height - 1)); + xf = IndexClamp((int)(x + 1), (p_im.size.width - 1)); + for (d = 0; d < COUNTC; d++) { - p11 = (float)p_im.p[y1][x1].c[d]; - p21 = (float)p_im.p[y2][x1].c[d]; - p12 = (float)p_im.p[y1][x2].c[d]; - p22 = (float)p_im.p[y2][x2].c[d]; - t = p11 * k11 + p21 * k21 + p12 * k12 + p22 * k22; - res.c[d] = ByteClamp((int)(t + 0.5)); + p11 = p_im.p[yi][xi].c[d]; + p12 = p_im.p[yi][xf].c[d]; + p21 = p_im.p[yf][xi].c[d]; + p22 = p_im.p[yf][xf].c[d]; + res.c[d] = ByteClamp((int)(dy2 * (dx2 * p11 + dx1 * p12) + dy1 * (dx2 * p21 + dx1 * p22) + 0.5f)); } res = IMTcalcS (res); @@ -272,7 +308,7 @@ GCIparams GCIcalcallparams(GCIparams params) int h, w; GCIcoord cmin1, cmax1, cmean1, cd1; GCIcoord cmin2, cmax2, cmean2, cd2; - float areai, areac, aream; + float areai, areac, aream, margin; params.rect1.p[1].x = params.rect1.p[0].x; params.rect1.p[1].y = params.rect1.p[2].y; @@ -340,6 +376,11 @@ GCIparams GCIcalcallparams(GCIparams params) } cmean2.x *= 0.25f; cmean2.y *= 0.25f; + margin = (float)params.margin * params.mi; + cmin2.x -= margin; + cmin2.y -= margin; + cmax2.x += margin; + cmax2.y += margin; cd2.x = cmax2.x - cmin2.x; cd2.y = cmax2.y - cmin2.y; params.rect2.min = cmin2; @@ -375,13 +416,16 @@ IMTimage IMTFilterGeoConform (IMTimage p_im, IMTimage d_im, GCIparams params) cf.y -= params.rect1.min.y; cf.x *= params.m; cf.y *= params.m; + cf.x -= 0.5f; + cf.y -= 0.5f; if (cf.x < 0 || cf.y < 0 || cf.x >= params.size1.height || cf.y >= params.size1.width) { d_im.p[i][j] = IMTset(0, 0, 0); } else { - d_im.p[i][j] = IMTinterpolation(p_im, cf); +// d_im.p[i][j] = IMTInterpolateBiLine(p_im, cf); + d_im.p[i][j] = IMTInterpolateBiCubic(p_im, cf); } } } diff --git a/src/geoconform.h b/src/geoconform.h index 0176af0..9a4f526 100644 --- a/src/geoconform.h +++ b/src/geoconform.h @@ -43,6 +43,7 @@ extern "C" { #define COUNTA 20 #define COUNTC 3 #define COUNTG 10 +#define COUNTM 0 typedef uint8_t BYTE; typedef uint16_t WORD; @@ -96,6 +97,7 @@ extern "C" { GCIrect rect1, rect2; float m, mi; int iters; + int margin; } GCIparams; @@ -108,7 +110,8 @@ extern "C" { IMTpixel IMTcalcS (IMTpixel); IMTimage IMTalloc (IMTsize, int); IMTimage IMTfree (IMTimage); - IMTpixel IMTinterpolation (IMTimage, GCIcoord); + IMTpixel IMTInterpolateBiCubic (IMTimage, GCIcoord); + IMTpixel IMTInterpolateBiLine (IMTimage, GCIcoord); GCIcoord GCIconformaltrans(GCIctrans, GCIcoord); GCIparams GCIcalcallparams(GCIparams); IMTimage IMTFilterGeoConform (IMTimage, IMTimage, GCIparams); diff --git a/src/geoconformimage.cpp b/src/geoconformimage.cpp index 0dbdf11..ff4ca89 100644 --- a/src/geoconformimage.cpp +++ b/src/geoconformimage.cpp @@ -28,6 +28,7 @@ void GeoConformImageUsage(const char *progname) printf("Usage : %s [options] \n", progname); printf("options:\n"); printf(" -i N iteration set (default = %d)\n", COUNTG); + printf(" -m N margin (default = %d)\n", COUNTM); printf(" -p str string conform params: \"A0,B0,A1,B1,[...,A9,B9]\"\n"); printf(" -r str string region image: \"Xws,Yws,Xne,Yne\"\n"); printf(" -h this help\n"); @@ -47,10 +48,11 @@ int main(int argc, char *argv[]) IMTimage imgin, imgout; bool fhelp = false; params.iters = COUNTG; + params.margin = COUNTM; GeoConformImageTitle(); - while ((opt = getopt(argc, argv, ":i:p:r:h")) != -1) + while ((opt = getopt(argc, argv, ":i:m:p:r:h")) != -1) { switch(opt) { @@ -59,6 +61,11 @@ int main(int argc, char *argv[]) if (params.iters < 2) params.iters = 2; printf("Parameter iters set %d.\n", params.iters); break; + case 'm': + params.margin = atoi(optarg); + if (params.margin < 0) params.margin = 0; + printf("Parameter margin set %d.\n", params.margin); + break; case 'p': params.trans.na = sscanf(optarg, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", ¶ms.trans.a[0], ¶ms.trans.a[1], ¶ms.trans.a[2], ¶ms.trans.a[3], ¶ms.trans.a[4], ¶ms.trans.a[5], ¶ms.trans.a[6], ¶ms.trans.a[7], ¶ms.trans.a[8], ¶ms.trans.a[9], ¶ms.trans.a[10], ¶ms.trans.a[11], ¶ms.trans.a[12], ¶ms.trans.a[13], ¶ms.trans.a[14], ¶ms.trans.a[15], ¶ms.trans.a[16], ¶ms.trans.a[17], ¶ms.trans.a[18], ¶ms.trans.a[19]); if (params.trans.na < 3)