From b74fad466b225b6c92e86bb52dbe49d739fc9e9f Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 13 Aug 2008 20:26:28 +0000 Subject: [PATCH] * Implement difference, multiply, divide, screen and overlay blend methods. git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2711 92316355-f0b4-4df1-b90c-862c8a59935f --- pipi/Makefile.am | 3 +- pipi/combine/mulscreen.c | 220 +++++++++++++++++++++++++++++++++++++++ pipi/combine/subadd.c | 63 +++++++++-- pipi/context.c | 89 ++++++++++++++-- pipi/pipi.h | 7 +- src/pipi.c | 29 +++++- 6 files changed, 394 insertions(+), 17 deletions(-) create mode 100644 pipi/combine/mulscreen.c diff --git a/pipi/Makefile.am b/pipi/Makefile.am index c0a8450..4a3e232 100644 --- a/pipi/Makefile.am +++ b/pipi/Makefile.am @@ -42,7 +42,8 @@ codec_sources = combine_sources = \ combine/mean.c \ combine/minmax.c \ - combine/subadd.c + combine/subadd.c \ + combine/mulscreen.c filter_sources = \ filter/autocontrast.c \ diff --git a/pipi/combine/mulscreen.c b/pipi/combine/mulscreen.c new file mode 100644 index 0000000..d9dc165 --- /dev/null +++ b/pipi/combine/mulscreen.c @@ -0,0 +1,220 @@ +/* + * libpipi Proper image processing implementation library + * Copyright (c) 2004-2008 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This library is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * mulscreen.c: multiply and screen computation functions + */ + +#include "config.h" +#include "common.h" + +#include "pipi.h" +#include "pipi_internals.h" + +pipi_image_t *pipi_multiply(pipi_image_t *img1, pipi_image_t *img2) +{ + pipi_image_t *dst; + pipi_pixels_t *img1p, *img2p, *dstp; + float *img1data, *img2data, *dstdata; + int x, y, w, h; + + if(img1->w != img2->w || img1->h != img2->h) + return NULL; + + w = img1->w; + h = img1->h; + + dst = pipi_new(w, h); + dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); + dstdata = (float *)dstp->pixels; + + img1p = pipi_getpixels(img1, PIPI_PIXELS_RGBA_F); + img1data = (float *)img1p->pixels; + img2p = pipi_getpixels(img2, PIPI_PIXELS_RGBA_F); + img2data = (float *)img2p->pixels; + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + float p, q; + + p = img1data[4 * (y * w + x)]; + q = img2data[4 * (y * w + x)]; + dstdata[4 * (y * w + x)] = p * q; + + p = img1data[4 * (y * w + x) + 1]; + q = img2data[4 * (y * w + x) + 1]; + dstdata[4 * (y * w + x) + 1] = p * q; + + p = img1data[4 * (y * w + x) + 2]; + q = img2data[4 * (y * w + x) + 2]; + dstdata[4 * (y * w + x) + 2] = p * q; + + p = img1data[4 * (y * w + x) + 3]; + q = img2data[4 * (y * w + x) + 3]; + dstdata[4 * (y * w + x) + 3] = p * q; + } + } + + return dst; +} + +pipi_image_t *pipi_divide(pipi_image_t *img1, pipi_image_t *img2) +{ + pipi_image_t *dst; + pipi_pixels_t *img1p, *img2p, *dstp; + float *img1data, *img2data, *dstdata; + int x, y, w, h; + + if(img1->w != img2->w || img1->h != img2->h) + return NULL; + + w = img1->w; + h = img1->h; + + dst = pipi_new(w, h); + dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); + dstdata = (float *)dstp->pixels; + + img1p = pipi_getpixels(img1, PIPI_PIXELS_RGBA_F); + img1data = (float *)img1p->pixels; + img2p = pipi_getpixels(img2, PIPI_PIXELS_RGBA_F); + img2data = (float *)img2p->pixels; + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + float p, q; + + p = img1data[4 * (y * w + x)]; + q = img2data[4 * (y * w + x)]; + dstdata[4 * (y * w + x)] = p >= q ? 1. : p / q; + + p = img1data[4 * (y * w + x) + 1]; + q = img2data[4 * (y * w + x) + 1]; + dstdata[4 * (y * w + x) + 1] = p >= q ? 1. : p / q; + + p = img1data[4 * (y * w + x) + 2]; + q = img2data[4 * (y * w + x) + 2]; + dstdata[4 * (y * w + x) + 2] = p >= q ? 1. : p / q; + + p = img1data[4 * (y * w + x) + 3]; + q = img2data[4 * (y * w + x) + 3]; + dstdata[4 * (y * w + x) + 3] = p >= q ? 1. : p / q; + } + } + + return dst; +} + +pipi_image_t *pipi_screen(pipi_image_t *img1, pipi_image_t *img2) +{ + pipi_image_t *dst; + pipi_pixels_t *img1p, *img2p, *dstp; + float *img1data, *img2data, *dstdata; + int x, y, w, h; + + if(img1->w != img2->w || img1->h != img2->h) + return NULL; + + w = img1->w; + h = img1->h; + + dst = pipi_new(w, h); + dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); + dstdata = (float *)dstp->pixels; + + img1p = pipi_getpixels(img1, PIPI_PIXELS_RGBA_F); + img1data = (float *)img1p->pixels; + img2p = pipi_getpixels(img2, PIPI_PIXELS_RGBA_F); + img2data = (float *)img2p->pixels; + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + float p, q; + + p = img1data[4 * (y * w + x)]; + q = img2data[4 * (y * w + x)]; + dstdata[4 * (y * w + x)] = p + q - p * q; + + p = img1data[4 * (y * w + x) + 1]; + q = img2data[4 * (y * w + x) + 1]; + dstdata[4 * (y * w + x) + 1] = p + q - p * q; + + p = img1data[4 * (y * w + x) + 2]; + q = img2data[4 * (y * w + x) + 2]; + dstdata[4 * (y * w + x) + 2] = p + q - p * q; + + p = img1data[4 * (y * w + x) + 3]; + q = img2data[4 * (y * w + x) + 3]; + dstdata[4 * (y * w + x) + 3] = p + q - p * q; + } + } + + return dst; +} + +pipi_image_t *pipi_overlay(pipi_image_t *img1, pipi_image_t *img2) +{ + pipi_image_t *dst; + pipi_pixels_t *img1p, *img2p, *dstp; + float *img1data, *img2data, *dstdata; + int x, y, w, h; + + if(img1->w != img2->w || img1->h != img2->h) + return NULL; + + w = img1->w; + h = img1->h; + + dst = pipi_new(w, h); + dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); + dstdata = (float *)dstp->pixels; + + img1p = pipi_getpixels(img1, PIPI_PIXELS_RGBA_F); + img1data = (float *)img1p->pixels; + img2p = pipi_getpixels(img2, PIPI_PIXELS_RGBA_F); + img2data = (float *)img2p->pixels; + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + float p, q; + + p = img1data[4 * (y * w + x)]; + q = img2data[4 * (y * w + x)]; + dstdata[4 * (y * w + x)] = p * (p + 2. * q * (1. - p)); + + p = img1data[4 * (y * w + x) + 1]; + q = img2data[4 * (y * w + x) + 1]; + dstdata[4 * (y * w + x) + 1] = p * (p + 2. * q * (1. - p)); + + p = img1data[4 * (y * w + x) + 2]; + q = img2data[4 * (y * w + x) + 2]; + dstdata[4 * (y * w + x) + 2] = p * (p + 2. * q * (1. - p)); + + p = img1data[4 * (y * w + x) + 3]; + q = img2data[4 * (y * w + x) + 3]; + dstdata[4 * (y * w + x) + 3] = p * (p + 2. * q * (1. - p)); + } + } + + return dst; +} + diff --git a/pipi/combine/subadd.c b/pipi/combine/subadd.c index 5496535..8093cc1 100644 --- a/pipi/combine/subadd.c +++ b/pipi/combine/subadd.c @@ -13,15 +13,66 @@ */ /* - * subadd.c: sub and add computation functions + * subadd.c: sub, add and difference computation functions */ #include "config.h" #include "common.h" +#include + #include "pipi.h" #include "pipi_internals.h" +pipi_image_t *pipi_add(pipi_image_t *img1, pipi_image_t *img2) +{ + pipi_image_t *dst; + pipi_pixels_t *img1p, *img2p, *dstp; + float *img1data, *img2data, *dstdata; + int x, y, w, h; + + if(img1->w != img2->w || img1->h != img2->h) + return NULL; + + w = img1->w; + h = img1->h; + + dst = pipi_new(w, h); + dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA_F); + dstdata = (float *)dstp->pixels; + + img1p = pipi_getpixels(img1, PIPI_PIXELS_RGBA_F); + img1data = (float *)img1p->pixels; + img2p = pipi_getpixels(img2, PIPI_PIXELS_RGBA_F); + img2data = (float *)img2p->pixels; + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + float p, q; + + p = img1data[4 * (y * w + x)]; + q = img2data[4 * (y * w + x)]; + dstdata[4 * (y * w + x)] = (p + q < 1.) ? p + q : 1.; + + p = img1data[4 * (y * w + x) + 1]; + q = img2data[4 * (y * w + x) + 1]; + dstdata[4 * (y * w + x) + 1] = (p + q < 1.) ? p + q : 1.; + + p = img1data[4 * (y * w + x) + 2]; + q = img2data[4 * (y * w + x) + 2]; + dstdata[4 * (y * w + x) + 2] = (p + q < 1.) ? p + q : 1.; + + p = img1data[4 * (y * w + x) + 3]; + q = img2data[4 * (y * w + x) + 3]; + dstdata[4 * (y * w + x) + 3] = (p + q < 1.) ? p + q : 1.; + } + } + + return dst; +} + pipi_image_t *pipi_sub(pipi_image_t *img1, pipi_image_t *img2) { pipi_image_t *dst; @@ -71,7 +122,7 @@ pipi_image_t *pipi_sub(pipi_image_t *img1, pipi_image_t *img2) return dst; } -pipi_image_t *pipi_add(pipi_image_t *img1, pipi_image_t *img2) +pipi_image_t *pipi_difference(pipi_image_t *img1, pipi_image_t *img2) { pipi_image_t *dst; pipi_pixels_t *img1p, *img2p, *dstp; @@ -101,19 +152,19 @@ pipi_image_t *pipi_add(pipi_image_t *img1, pipi_image_t *img2) p = img1data[4 * (y * w + x)]; q = img2data[4 * (y * w + x)]; - dstdata[4 * (y * w + x)] = (p + q < 1.) ? p + q : 1.; + dstdata[4 * (y * w + x)] = fabsf(p - q); p = img1data[4 * (y * w + x) + 1]; q = img2data[4 * (y * w + x) + 1]; - dstdata[4 * (y * w + x) + 1] = (p + q < 1.) ? p + q : 1.; + dstdata[4 * (y * w + x) + 1] = fabsf(p - q); p = img1data[4 * (y * w + x) + 2]; q = img2data[4 * (y * w + x) + 2]; - dstdata[4 * (y * w + x) + 2] = (p + q < 1.) ? p + q : 1.; + dstdata[4 * (y * w + x) + 2] = fabsf(p - q); p = img1data[4 * (y * w + x) + 3]; q = img2data[4 * (y * w + x) + 3]; - dstdata[4 * (y * w + x) + 3] = (p + q < 1.) ? p + q : 1.; + dstdata[4 * (y * w + x) + 3] = fabsf(p - q); } } diff --git a/pipi/context.c b/pipi/context.c index e63bc7d..4ce2df3 100644 --- a/pipi/context.c +++ b/pipi/context.c @@ -146,13 +146,28 @@ int pipi_command(pipi_context_t *ctx, char const *cmd, ...) ctx->images[ctx->nimages - 2] = dst; ctx->nimages--; } - else if(!strcmp(cmd, "sub")) + else if(!strcmp(cmd, "min")) { pipi_image_t *dst; if(ctx->nimages < 2) return -1; - dst = pipi_sub(ctx->images[ctx->nimages - 2], + dst = pipi_min(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); + if(dst == NULL) + return -1; + pipi_free(ctx->images[ctx->nimages - 2]); + pipi_free(ctx->images[ctx->nimages - 1]); + ctx->images[ctx->nimages - 2] = dst; + ctx->nimages--; + } + else if(!strcmp(cmd, "max")) + { + pipi_image_t *dst; + + if(ctx->nimages < 2) + return -1; + dst = pipi_max(ctx->images[ctx->nimages - 2], ctx->images[ctx->nimages - 1]); if(dst == NULL) return -1; @@ -176,13 +191,13 @@ int pipi_command(pipi_context_t *ctx, char const *cmd, ...) ctx->images[ctx->nimages - 2] = dst; ctx->nimages--; } - else if(!strcmp(cmd, "min")) + else if(!strcmp(cmd, "sub")) { pipi_image_t *dst; if(ctx->nimages < 2) return -1; - dst = pipi_min(ctx->images[ctx->nimages - 2], + dst = pipi_sub(ctx->images[ctx->nimages - 2], ctx->images[ctx->nimages - 1]); if(dst == NULL) return -1; @@ -191,14 +206,74 @@ int pipi_command(pipi_context_t *ctx, char const *cmd, ...) ctx->images[ctx->nimages - 2] = dst; ctx->nimages--; } - else if(!strcmp(cmd, "max")) + else if(!strcmp(cmd, "difference")) { pipi_image_t *dst; if(ctx->nimages < 2) return -1; - dst = pipi_max(ctx->images[ctx->nimages - 2], - ctx->images[ctx->nimages - 1]); + dst = pipi_difference(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); + if(dst == NULL) + return -1; + pipi_free(ctx->images[ctx->nimages - 2]); + pipi_free(ctx->images[ctx->nimages - 1]); + ctx->images[ctx->nimages - 2] = dst; + ctx->nimages--; + } + else if(!strcmp(cmd, "multiply")) + { + pipi_image_t *dst; + + if(ctx->nimages < 2) + return -1; + dst = pipi_multiply(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); + if(dst == NULL) + return -1; + pipi_free(ctx->images[ctx->nimages - 2]); + pipi_free(ctx->images[ctx->nimages - 1]); + ctx->images[ctx->nimages - 2] = dst; + ctx->nimages--; + } + else if(!strcmp(cmd, "divide")) + { + pipi_image_t *dst; + + if(ctx->nimages < 2) + return -1; + dst = pipi_divide(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); + if(dst == NULL) + return -1; + pipi_free(ctx->images[ctx->nimages - 2]); + pipi_free(ctx->images[ctx->nimages - 1]); + ctx->images[ctx->nimages - 2] = dst; + ctx->nimages--; + } + else if(!strcmp(cmd, "screen")) + { + pipi_image_t *dst; + + if(ctx->nimages < 2) + return -1; + dst = pipi_screen(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); + if(dst == NULL) + return -1; + pipi_free(ctx->images[ctx->nimages - 2]); + pipi_free(ctx->images[ctx->nimages - 1]); + ctx->images[ctx->nimages - 2] = dst; + ctx->nimages--; + } + else if(!strcmp(cmd, "overlay")) + { + pipi_image_t *dst; + + if(ctx->nimages < 2) + return -1; + dst = pipi_overlay(ctx->images[ctx->nimages - 2], + ctx->images[ctx->nimages - 1]); if(dst == NULL) return -1; pipi_free(ctx->images[ctx->nimages - 2]); diff --git a/pipi/pipi.h b/pipi/pipi.h index 7f5a375..545c08b 100644 --- a/pipi/pipi.h +++ b/pipi/pipi.h @@ -88,8 +88,13 @@ extern pipi_image_t *pipi_resize(pipi_image_t *, int, int); extern pipi_image_t *pipi_mean(pipi_image_t *, pipi_image_t *); extern pipi_image_t *pipi_min(pipi_image_t *, pipi_image_t *); extern pipi_image_t *pipi_max(pipi_image_t *, pipi_image_t *); -extern pipi_image_t *pipi_sub(pipi_image_t *, pipi_image_t *); extern pipi_image_t *pipi_add(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_sub(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_difference(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_multiply(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_divide(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_screen(pipi_image_t *, pipi_image_t *); +extern pipi_image_t *pipi_overlay(pipi_image_t *, pipi_image_t *); extern pipi_image_t *pipi_convolution(pipi_image_t *, int, int, double[]); extern pipi_image_t *pipi_gaussian_blur(pipi_image_t *, float); diff --git a/src/pipi.c b/src/pipi.c index 28095db..08bb405 100644 --- a/src/pipi.c +++ b/src/pipi.c @@ -71,14 +71,39 @@ int main(int argc, char *argv[]) if(pipi_command(ctx, "max") != 0) return EXIT_FAILURE; } + else if(!strcmp(argv[0], "--add")) + { + if(pipi_command(ctx, "add") != 0) + return EXIT_FAILURE; + } else if(!strcmp(argv[0], "--sub")) { if(pipi_command(ctx, "sub") != 0) return EXIT_FAILURE; } - else if(!strcmp(argv[0], "--add")) + else if(!strcmp(argv[0], "--difference")) { - if(pipi_command(ctx, "add") != 0) + if(pipi_command(ctx, "difference") != 0) + return EXIT_FAILURE; + } + else if(!strcmp(argv[0], "--multiply")) + { + if(pipi_command(ctx, "multiply") != 0) + return EXIT_FAILURE; + } + else if(!strcmp(argv[0], "--divide")) + { + if(pipi_command(ctx, "divide") != 0) + return EXIT_FAILURE; + } + else if(!strcmp(argv[0], "--screen")) + { + if(pipi_command(ctx, "screen") != 0) + return EXIT_FAILURE; + } + else if(!strcmp(argv[0], "--overlay")) + { + if(pipi_command(ctx, "overlay") != 0) return EXIT_FAILURE; } else if(!strcmp(argv[0], "--output") || !strcmp(argv[0], "-o"))