| @@ -34,10 +34,7 @@ Image: | |||
| · context.cpp | |||
| · dither/dbs.cpp | |||
| · filter/blur.cpp | |||
| · filter/color.cpp | |||
| · filter/dilate.cpp | |||
| · filter/rotate.cpp | |||
| · filter/sharpen.cpp | |||
| · filter/transform.cpp | |||
| · filter/wave.cpp | |||
| · paint/bezier.cpp | |||
| @@ -52,5 +49,4 @@ Image: | |||
| · resample/bicubic.cpp | |||
| · resample/bresenham.cpp | |||
| · sequence.cpp | |||
| · tiles.cpp | |||
| @@ -119,8 +119,8 @@ liblolcore_sources = \ | |||
| image/color/cie1931.cpp image/color/color.cpp \ | |||
| image/dither/random.cpp image/dither/ediff.cpp \ | |||
| image/dither/ostromoukhov.cpp image/dither/ordered.cpp \ | |||
| image/filter/autocontrast.cpp image/filter/convolution.cpp \ | |||
| image/filter/median.cpp image/filter/yuv.cpp \ | |||
| image/filter/convolution.cpp image/filter/color.cpp \ | |||
| image/filter/dilate.cpp image/filter/median.cpp image/filter/yuv.cpp \ | |||
| image/render/noise.cpp \ | |||
| \ | |||
| loldebug.h \ | |||
| @@ -57,7 +57,7 @@ static inline vec3 GetDiffusion(float v) | |||
| if (v < 0.f) | |||
| v = 0.f; | |||
| for (int i = 1; i < sizeof(table) / sizeof(table[0]); ++i) | |||
| for (unsigned int i = 1; i < sizeof(table) / sizeof(table[0]); ++i) | |||
| { | |||
| if (v <= table[i][0]) | |||
| { | |||
| @@ -1,75 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; 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://www.wtfpl.net/ for more details. | |||
| // | |||
| #if defined HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include "core.h" | |||
| /* | |||
| * Autocontrast functions | |||
| * TODO: the current approach is naive; we should use the histogram in order | |||
| * to decide how to change the contrast. | |||
| */ | |||
| namespace lol | |||
| { | |||
| Image Image::AutoContrast() const | |||
| { | |||
| Image ret = *this; | |||
| float min_val = 1.f, max_val = 0.f; | |||
| int count = GetSize().x * GetSize().y; | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| { | |||
| min_val = lol::min(min_val, pixels[n]); | |||
| max_val = lol::max(max_val, pixels[n]); | |||
| } | |||
| float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f; | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = (pixels[n] - min_val) * t; | |||
| ret.Unlock(pixels); | |||
| } | |||
| else | |||
| { | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| { | |||
| min_val = lol::min(min_val, pixels[n].r); | |||
| min_val = lol::min(min_val, pixels[n].g); | |||
| min_val = lol::min(min_val, pixels[n].b); | |||
| max_val = lol::max(max_val, pixels[n].r); | |||
| max_val = lol::max(max_val, pixels[n].g); | |||
| max_val = lol::max(max_val, pixels[n].b); | |||
| } | |||
| float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f; | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4((pixels[n].r - min_val) * t, | |||
| (pixels[n].g - min_val) * t, | |||
| (pixels[n].b - min_val) * t, | |||
| pixels[n].a);; | |||
| ret.Unlock(pixels); | |||
| } | |||
| return ret; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -1,288 +1,191 @@ | |||
| /* | |||
| * libpipi Pathetic image processing interface library | |||
| * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org> | |||
| * 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. | |||
| */ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; 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://www.wtfpl.net/ for more details. | |||
| // | |||
| #if defined HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include "core.h" | |||
| /* | |||
| * color.c: colour manipulation functions | |||
| * Colour manipulation functions | |||
| */ | |||
| #include "config.h" | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include "pipi.h" | |||
| #include "pipi-internals.h" | |||
| pipi_image_t *pipi_brightness(pipi_image_t *src, double val) | |||
| namespace lol | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, gray; | |||
| w = src->w; | |||
| h = src->h; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| Image Image::Brightness(float val) const | |||
| { | |||
| Image ret = *this; | |||
| int count = GetSize().x * GetSize().y; | |||
| if(val >= 0.0) | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| if(gray) | |||
| { | |||
| double p = srcdata[y * w + x]; | |||
| dstdata[y * w + x] = p < 1. - val ? p + val : 1.; | |||
| } | |||
| else | |||
| { | |||
| double p; | |||
| int d = 4 * (y * w + x); | |||
| p = srcdata[d]; | |||
| dstdata[d] = p < 1. - val ? p + val : 1.; | |||
| p = srcdata[d + 1]; | |||
| dstdata[d + 1] = p < 1. - val ? p + val : 1.; | |||
| p = srcdata[d + 2]; | |||
| dstdata[d + 2] = p < 1. - val ? p + val : 1.; | |||
| p = srcdata[d + 3]; | |||
| dstdata[d + 3] = p; | |||
| } | |||
| } | |||
| } | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = lol::clamp(pixels[n] + val, 0.f, 1.f); | |||
| ret.Unlock(pixels); | |||
| } | |||
| else | |||
| { | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| if(gray) | |||
| { | |||
| double p = srcdata[y * w + x]; | |||
| dstdata[y * w + x] = p > -val ? p + val : 0.; | |||
| } | |||
| else | |||
| { | |||
| double p; | |||
| int d = 4 * (y * w + x); | |||
| p = srcdata[d]; | |||
| dstdata[d] = p > -val ? p + val : 0.; | |||
| p = srcdata[d + 1]; | |||
| dstdata[d + 1] = p > -val ? p + val : 0.; | |||
| p = srcdata[d + 2]; | |||
| dstdata[d + 2] = p > -val ? p + val : 0.; | |||
| p = srcdata[d + 3]; | |||
| dstdata[d + 3] = p; | |||
| } | |||
| } | |||
| } | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4(lol::clamp(pixels[n].rgb + vec3(val), 0.f, 1.f), | |||
| pixels[n].a); | |||
| ret.Unlock(pixels); | |||
| } | |||
| return dst; | |||
| return ret; | |||
| } | |||
| pipi_image_t *pipi_contrast(pipi_image_t *src, double val) | |||
| Image Image::Contrast(float val) const | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, gray; | |||
| Image ret = *this; | |||
| int count = GetSize().x * GetSize().y; | |||
| w = src->w; | |||
| h = src->h; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| if(val >= 0.0) | |||
| if (val >= 0.f) | |||
| { | |||
| if(val > 0.99999) | |||
| val = 0.99999; | |||
| val = 1. / (1. - val); | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| if(gray) | |||
| { | |||
| double p = (srcdata[y * w + x] - 0.5) * val + 0.5; | |||
| dstdata[y * w + x] = p < 0. ? 0. : p > 1. ? 1. : p; | |||
| } | |||
| else | |||
| { | |||
| double p; | |||
| int d = 4 * (y * w + x); | |||
| if (val > 0.99999f) | |||
| val = 0.99999f; | |||
| p = (srcdata[d] - 0.5) * val + 0.5; | |||
| dstdata[d] = p < 0. ? 0. : p > 1. ? 1. : p; | |||
| p = (srcdata[d + 1] - 0.5) * val + 0.5; | |||
| dstdata[d + 1] = p < 0. ? 0. : p > 1. ? 1. : p; | |||
| p = (srcdata[d + 2] - 0.5) * val + 0.5; | |||
| dstdata[d + 2] = p < 0. ? 0. : p > 1. ? 1. : p; | |||
| p = srcdata[d + 3]; | |||
| dstdata[d + 3] = p; | |||
| } | |||
| } | |||
| } | |||
| val = 1.f / (1.f - val); | |||
| } | |||
| else | |||
| { | |||
| if(val < -1.) | |||
| val = -1.; | |||
| val = 1. + val; | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| if(gray) | |||
| { | |||
| double p = srcdata[y * w + x]; | |||
| dstdata[y * w + x] = (p - 0.5) * val + 0.5; | |||
| } | |||
| else | |||
| { | |||
| double p; | |||
| int d = 4 * (y * w + x); | |||
| val = lol::clamp(1.f + val, 0.f, 1.f); | |||
| } | |||
| p = srcdata[d]; | |||
| dstdata[d] = (p - 0.5) * val + 0.5; | |||
| p = srcdata[d + 1]; | |||
| dstdata[d + 1] = (p - 0.5) * val + 0.5; | |||
| p = srcdata[d + 2]; | |||
| dstdata[d + 2] = (p - 0.5) * val + 0.5; | |||
| p = srcdata[d + 3]; | |||
| dstdata[d + 3] = p; | |||
| } | |||
| } | |||
| } | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| float add = -0.5f * val + 0.5f; | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = lol::clamp(pixels[n] * val + add, 0.f, 1.f); | |||
| ret.Unlock(pixels); | |||
| } | |||
| else | |||
| { | |||
| vec3 add = vec3(-0.5f * val + 0.5f); | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4(lol::clamp(pixels[n].rgb * val + add, 0.f, 1.f), | |||
| pixels[n].a); | |||
| ret.Unlock(pixels); | |||
| } | |||
| return dst; | |||
| return ret; | |||
| } | |||
| pipi_image_t *pipi_invert(pipi_image_t *src) | |||
| /* | |||
| * TODO: the current approach is naive; we should use the histogram in order | |||
| * to decide how to change the contrast. | |||
| */ | |||
| Image Image::AutoContrast() const | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, gray; | |||
| w = src->w; | |||
| h = src->h; | |||
| Image ret = *this; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| float min_val = 1.f, max_val = 0.f; | |||
| int count = GetSize().x * GetSize().y; | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| { | |||
| min_val = lol::min(min_val, pixels[n]); | |||
| max_val = lol::max(max_val, pixels[n]); | |||
| } | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f; | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = (pixels[n] - min_val) * t; | |||
| for(y = 0; y < h; y++) | |||
| ret.Unlock(pixels); | |||
| } | |||
| else | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| { | |||
| if(gray) | |||
| { | |||
| dstdata[y * w + x] = 1. - srcdata[y * w + x]; | |||
| } | |||
| else | |||
| { | |||
| int d = 4 * (y * w + x); | |||
| dstdata[d] = 1. - srcdata[d]; | |||
| dstdata[d + 1] = 1. - srcdata[d + 1]; | |||
| dstdata[d + 2] = 1. - srcdata[d + 2]; | |||
| dstdata[d + 3] = 1. - srcdata[d + 3]; | |||
| } | |||
| min_val = lol::min(min_val, pixels[n].r); | |||
| min_val = lol::min(min_val, pixels[n].g); | |||
| min_val = lol::min(min_val, pixels[n].b); | |||
| max_val = lol::max(max_val, pixels[n].r); | |||
| max_val = lol::max(max_val, pixels[n].g); | |||
| max_val = lol::max(max_val, pixels[n].b); | |||
| } | |||
| float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f; | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4((pixels[n].r - min_val) * t, | |||
| (pixels[n].g - min_val) * t, | |||
| (pixels[n].b - min_val) * t, | |||
| pixels[n].a);; | |||
| ret.Unlock(pixels); | |||
| } | |||
| return dst; | |||
| return ret; | |||
| } | |||
| pipi_image_t *pipi_threshold(pipi_image_t *src, double val) | |||
| Image Image::Invert() const | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, gray; | |||
| w = src->w; | |||
| h = src->h; | |||
| Image ret = *this; | |||
| int count = GetSize().x * GetSize().y; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = 1.f - pixels[n]; | |||
| ret.Unlock(pixels); | |||
| } | |||
| else | |||
| { | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4(vec3(1.f) -pixels[n].rgb, pixels[n].a); | |||
| ret.Unlock(pixels); | |||
| } | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| return ret; | |||
| } | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| Image Image::Threshold(float val) const | |||
| { | |||
| Image ret = *this; | |||
| int count = GetSize().x * GetSize().y; | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| if(gray) | |||
| { | |||
| dstdata[y * w + x] = srcdata[y * w + x] < val ? 0. : 1.; | |||
| } | |||
| else | |||
| { | |||
| int d = 4 * (y * w + x); | |||
| float *pixels = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = pixels[n] > val ? 1.f : 0.f; | |||
| ret.Unlock(pixels); | |||
| dstdata[d] = srcdata[d] < val ? 0. : 1.; | |||
| dstdata[d + 1] = srcdata[d + 1] < val ? 0. : 1.; | |||
| dstdata[d + 2] = srcdata[d + 2] < val ? 0. : 1.; | |||
| dstdata[d + 3] = srcdata[d + 3] < val ? 0. : 1.; | |||
| } | |||
| } | |||
| } | |||
| return ret; | |||
| } | |||
| return dst; | |||
| Image Image::Threshold(vec3 val) const | |||
| { | |||
| Image ret = *this; | |||
| int count = GetSize().x * GetSize().y; | |||
| vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int n = 0; n < count; ++n) | |||
| pixels[n] = vec4(pixels[n].r > val.r ? 1.f : 0.f, | |||
| pixels[n].g > val.g ? 1.f : 0.f, | |||
| pixels[n].b > val.b ? 1.f : 0.f, | |||
| pixels[n].a); | |||
| ret.Unlock(pixels); | |||
| return ret; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -83,6 +83,22 @@ Image Image::Convolution(Array2D<float> const &kernel) | |||
| } | |||
| } | |||
| Image Image::Sharpen(Array2D<float> const &kernel) | |||
| { | |||
| ivec2 ksize = kernel.GetSize(); | |||
| Array2D<float> newkernel(ksize); | |||
| for (int dy = 0; dy < ksize.y; ++dy) | |||
| for (int dx = 0; dx < ksize.x; ++dx) | |||
| { | |||
| newkernel[dx][dy] = - kernel[dx][dy]; | |||
| if (dx == ksize.x / 2 && dy == ksize.y / 2) | |||
| newkernel[dx][dy] += 2.f; | |||
| } | |||
| return Convolution(newkernel); | |||
| } | |||
| template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y> | |||
| static Image NonSepConv(Image &src, Array2D<float> const &kernel) | |||
| { | |||
| @@ -1,170 +1,144 @@ | |||
| /* | |||
| * libpipi Pathetic image processing interface library | |||
| * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org> | |||
| * 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. | |||
| */ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; 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://www.wtfpl.net/ for more details. | |||
| // | |||
| #if defined HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include "core.h" | |||
| /* | |||
| * dilate.c: dilate and erode functions | |||
| * Dilate and erode functions | |||
| */ | |||
| #include "config.h" | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include "pipi.h" | |||
| #include "pipi-internals.h" | |||
| /* FIXME: these functions are almost the same, try to merge them | |||
| * somewhat efficiently. */ | |||
| /* TODO: - dilate by k (Manhattan distance) | |||
| * - dilate by r (euclidian distance, with non-integer r) */ | |||
| pipi_image_t *pipi_dilate(pipi_image_t *src) | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, i, gray; | |||
| w = src->w; | |||
| h = src->h; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| namespace lol | |||
| { | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| Image Image::Dilate() | |||
| { | |||
| ivec2 const size = GetSize(); | |||
| Image ret(size); | |||
| for(y = 0; y < h; y++) | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| double t; | |||
| int x2, y2, x3, y3; | |||
| y2 = y - 1; | |||
| if(y2 < 0) y2 = h - 1; | |||
| y3 = y + 1; | |||
| if(y3 >= h) y3 = 0; | |||
| x2 = x - 1; | |||
| if(x2 < 0) x2 = w - 1; | |||
| x3 = x + 1; | |||
| if(x3 >= w) x3 = 0; | |||
| if(gray) | |||
| float const *srcp = Lock<PixelFormat::Y_F32>(); | |||
| float *dstp = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int y = 0; y < size.y; ++y) | |||
| for (int x = 0; x < size.x; ++x) | |||
| { | |||
| t = srcdata[y * w + x]; | |||
| if(srcdata[y2 * w + x] > t) t = srcdata[y2 * w + x]; | |||
| if(srcdata[y3 * w + x] > t) t = srcdata[y3 * w + x]; | |||
| if(srcdata[y * w + x2] > t) t = srcdata[y * w + x2]; | |||
| if(srcdata[y * w + x3] > t) t = srcdata[y * w + x3]; | |||
| dstdata[y * w + x] = t; | |||
| int y2 = lol::max(y - 1, 0); | |||
| int x2 = lol::max(x - 1, 0); | |||
| int y3 = lol::min(y + 1, size.y - 1); | |||
| int x3 = lol::min(x + 1, size.x - 1); | |||
| float t = srcp[y * size.x + x]; | |||
| t = lol::max(t, srcp[y * size.x + x2]); | |||
| t = lol::max(t, srcp[y * size.x + x3]); | |||
| t = lol::max(t, srcp[y2 * size.x + x]); | |||
| t = lol::max(t, srcp[y3 * size.x + x]); | |||
| dstp[y * size.x + x] = t; | |||
| } | |||
| else | |||
| Unlock(srcp); | |||
| ret.Unlock(dstp); | |||
| } | |||
| else | |||
| { | |||
| vec4 const *srcp = Lock<PixelFormat::RGBA_F32>(); | |||
| vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int y = 0; y < size.y; ++y) | |||
| for (int x = 0; x < size.x; ++x) | |||
| { | |||
| for(i = 0; i < 4; i++) | |||
| { | |||
| t = srcdata[4 * (y * w + x) + i]; | |||
| if(srcdata[4 * (y2 * w + x) + i] > t) | |||
| t = srcdata[4 * (y2 * w + x) + i]; | |||
| if(srcdata[4 * (y3 * w + x) + i] > t) | |||
| t = srcdata[4 * (y3 * w + x) + i]; | |||
| if(srcdata[4 * (y * w + x2) + i] > t) | |||
| t = srcdata[4 * (y * w + x2) + i]; | |||
| if(srcdata[4 * (y * w + x3) + i] > t) | |||
| t = srcdata[4 * (y * w + x3) + i]; | |||
| dstdata[4 * (y * w + x) + i] = t; | |||
| } | |||
| int y2 = lol::max(y - 1, 0); | |||
| int x2 = lol::max(x - 1, 0); | |||
| int y3 = lol::min(y + 1, size.y - 1); | |||
| int x3 = lol::min(x + 1, size.x - 1); | |||
| vec3 t = srcp[y * size.x + x].rgb; | |||
| t = lol::max(t, srcp[y * size.x + x2].rgb); | |||
| t = lol::max(t, srcp[y * size.x + x3].rgb); | |||
| t = lol::max(t, srcp[y2 * size.x + x].rgb); | |||
| t = lol::max(t, srcp[y3 * size.x + x].rgb); | |||
| dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a); | |||
| } | |||
| } | |||
| Unlock(srcp); | |||
| ret.Unlock(dstp); | |||
| } | |||
| return dst; | |||
| return ret; | |||
| } | |||
| pipi_image_t *pipi_erode(pipi_image_t *src) | |||
| Image Image::Erode() | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| int x, y, w, h, i, gray; | |||
| w = src->w; | |||
| h = src->h; | |||
| gray = (src->last_modified == PIPI_PIXELS_Y_F32); | |||
| ivec2 const size = GetSize(); | |||
| Image ret(size); | |||
| srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); | |||
| srcdata = (float *)srcp->pixels; | |||
| dst = pipi_new(w, h); | |||
| dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32) | |||
| : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); | |||
| dstdata = (float *)dstp->pixels; | |||
| for(y = 0; y < h; y++) | |||
| if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| double t; | |||
| int x2, y2, x3, y3; | |||
| y2 = y - 1; | |||
| if(y2 < 0) y2 = h - 1; | |||
| y3 = y + 1; | |||
| if(y3 >= h) y3 = 0; | |||
| x2 = x - 1; | |||
| if(x2 < 0) x2 = w - 1; | |||
| x3 = x + 1; | |||
| if(x3 >= w) x3 = 0; | |||
| if(gray) | |||
| float const *srcp = Lock<PixelFormat::Y_F32>(); | |||
| float *dstp = ret.Lock<PixelFormat::Y_F32>(); | |||
| for (int y = 0; y < size.y; ++y) | |||
| for (int x = 0; x < size.x; ++x) | |||
| { | |||
| t = srcdata[y * w + x]; | |||
| if(srcdata[y2 * w + x] < t) t = srcdata[y2 * w + x]; | |||
| if(srcdata[y3 * w + x] < t) t = srcdata[y3 * w + x]; | |||
| if(srcdata[y * w + x2] < t) t = srcdata[y * w + x2]; | |||
| if(srcdata[y * w + x3] < t) t = srcdata[y * w + x3]; | |||
| dstdata[y * w + x] = t; | |||
| int y2 = lol::max(y - 1, 0); | |||
| int x2 = lol::max(x - 1, 0); | |||
| int y3 = lol::min(y + 1, size.y - 1); | |||
| int x3 = lol::min(x + 1, size.x - 1); | |||
| float t = srcp[y * size.x + x]; | |||
| t = lol::max(t, srcp[y * size.x + x2]); | |||
| t = lol::max(t, srcp[y * size.x + x3]); | |||
| t = lol::max(t, srcp[y2 * size.x + x]); | |||
| t = lol::max(t, srcp[y3 * size.x + x]); | |||
| dstp[y * size.x + x] = t; | |||
| } | |||
| else | |||
| Unlock(srcp); | |||
| ret.Unlock(dstp); | |||
| } | |||
| else | |||
| { | |||
| vec4 const *srcp = Lock<PixelFormat::RGBA_F32>(); | |||
| vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>(); | |||
| for (int y = 0; y < size.y; ++y) | |||
| for (int x = 0; x < size.x; ++x) | |||
| { | |||
| for(i = 0; i < 4; i++) | |||
| { | |||
| t = srcdata[4 * (y * w + x) + i]; | |||
| if(srcdata[4 * (y2 * w + x) + i] < t) | |||
| t = srcdata[4 * (y2 * w + x) + i]; | |||
| if(srcdata[4 * (y3 * w + x) + i] < t) | |||
| t = srcdata[4 * (y3 * w + x) + i]; | |||
| if(srcdata[4 * (y * w + x2) + i] < t) | |||
| t = srcdata[4 * (y * w + x2) + i]; | |||
| if(srcdata[4 * (y * w + x3) + i] < t) | |||
| t = srcdata[4 * (y * w + x3) + i]; | |||
| dstdata[4 * (y * w + x) + i] = t; | |||
| } | |||
| int y2 = lol::max(y - 1, 0); | |||
| int x2 = lol::max(x - 1, 0); | |||
| int y3 = lol::min(y + 1, size.y - 1); | |||
| int x3 = lol::min(x + 1, size.x - 1); | |||
| vec3 t = srcp[y * size.x + x].rgb; | |||
| t = lol::min(t, srcp[y * size.x + x2].rgb); | |||
| t = lol::min(t, srcp[y * size.x + x3].rgb); | |||
| t = lol::min(t, srcp[y2 * size.x + x].rgb); | |||
| t = lol::min(t, srcp[y3 * size.x + x].rgb); | |||
| dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a); | |||
| } | |||
| } | |||
| Unlock(srcp); | |||
| ret.Unlock(dstp); | |||
| } | |||
| return dst; | |||
| return ret; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -1,128 +0,0 @@ | |||
| /* | |||
| * libpipi Pathetic image processing interface library | |||
| * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org> | |||
| * 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. | |||
| */ | |||
| /* | |||
| * sharpen.c: sharpen functions | |||
| */ | |||
| #include "config.h" | |||
| #include "common.h" | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #ifndef M_PI | |||
| # define M_PI 3.14159265358979323846 | |||
| #endif | |||
| #include "pipi.h" | |||
| #include "pipi-internals.h" | |||
| pipi_image_t *pipi_gaussian_sharpen(pipi_image_t *src, float radius) | |||
| { | |||
| pipi_image_t *dst; | |||
| pipi_pixels_t *srcp, *dstp; | |||
| float *srcdata, *dstdata; | |||
| double *kernel, *buffer; | |||
| double K, L; | |||
| int x, y, i, w, h, kr, kw; | |||
| w = src->w; | |||
| h = src->h; | |||
| srcp = pipi_get_pixels(src, PIPI_PIXELS_RGBA_F); | |||
| srcdata = (float *)srcp->pixels; | |||
| dst = pipi_new(w, h); | |||
| dstp = pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F); | |||
| dstdata = (float *)dstp->pixels; | |||
| kr = (int)(3. * radius + 0.99999); | |||
| kw = 2 * kr + 1; | |||
| K = 1. / (sqrt(2. * M_PI) * radius); | |||
| L = -1. / (2. * radius * radius); | |||
| kernel = malloc(kw * sizeof(double)); | |||
| for(i = -kr; i <= kr; i++) | |||
| kernel[i + kr] = exp(L * i * i) * K; | |||
| buffer = malloc(w * h * 4 * sizeof(double)); | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| double R = 0., G = 0., B = 0., t = 0.; | |||
| int x2, off = 4 * (y * w + x); | |||
| for(i = -kr; i <= kr; i++) | |||
| { | |||
| double f = kernel[i + kr]; | |||
| x2 = x + i; | |||
| if(x2 < 0) x2 = 0; | |||
| else if(x2 >= w) x2 = w - 1; | |||
| R += f * srcdata[(y * w + x2) * 4]; | |||
| G += f * srcdata[(y * w + x2) * 4 + 1]; | |||
| B += f * srcdata[(y * w + x2) * 4 + 2]; | |||
| t += f; | |||
| } | |||
| buffer[off] = R / t; | |||
| buffer[off + 1] = G / t; | |||
| buffer[off + 2] = B / t; | |||
| } | |||
| } | |||
| for(y = 0; y < h; y++) | |||
| { | |||
| for(x = 0; x < w; x++) | |||
| { | |||
| double R = 0., G = 0., B = 0., t = 0.; | |||
| int y2, off = 4 * (y * w + x); | |||
| for(i = -kr; i <= kr; i++) | |||
| { | |||
| double f = kernel[i + kr]; | |||
| y2 = y + i; | |||
| if(y2 < 0) y2 = 0; | |||
| else if(y2 >= h) y2 = h - 1; | |||
| R += f * buffer[(y2 * w + x) * 4]; | |||
| G += f * buffer[(y2 * w + x) * 4 + 1]; | |||
| B += f * buffer[(y2 * w + x) * 4 + 2]; | |||
| t += f; | |||
| } | |||
| dstdata[off] = 2 * srcdata[off] - R / t; | |||
| if(dstdata[off] < 0.0) dstdata[off] = 0.0; | |||
| if(dstdata[off] > 1.0) dstdata[off] = 1.0; | |||
| dstdata[off + 1] = 2 * srcdata[off + 1 ] - G / t; | |||
| if(dstdata[off + 1] < 0.0) dstdata[off + 1] = 0.0; | |||
| if(dstdata[off + 1] > 1.0) dstdata[off + 1] = 1.0; | |||
| dstdata[off + 2] = 2 * srcdata[off + 2 ] - B / t; | |||
| if(dstdata[off + 2] < 0.0) dstdata[off + 2] = 0.0; | |||
| if(dstdata[off + 2] > 1.0) dstdata[off + 2] = 1.0; | |||
| } | |||
| } | |||
| free(buffer); | |||
| free(kernel); | |||
| return dst; | |||
| } | |||
| @@ -1,111 +0,0 @@ | |||
| /* | |||
| * libpipi Pathetic image processing interface library | |||
| * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org> | |||
| * 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. | |||
| */ | |||
| /* | |||
| * tiles.c: the tiles system | |||
| */ | |||
| #include "config.h" | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "pipi.h" | |||
| #include "pipi-internals.h" | |||
| #ifdef USE_TILES | |||
| pipi_tile_t *pipi_get_tile(pipi_image_t *img, int x, int y, int zoom, | |||
| pipi_format_t fmt, int plane) | |||
| { | |||
| pipi_tile_t * ret; | |||
| int i; | |||
| /* If the tile already exists, return it. */ | |||
| for(i = 0; i < img->ntiles; i++) | |||
| { | |||
| if(img->tiles[i]->x == x && img->tiles[i]->y == y | |||
| && img->tiles[i]->fmt == fmt | |||
| && img->tiles[i]->zoom == zoom | |||
| && img->tiles[i]->plane == plane) | |||
| { | |||
| img->tiles[i]->refcount++; | |||
| return img->tiles[i]; | |||
| } | |||
| } | |||
| /* Create a tile. When the image provides a tile creation function, | |||
| * we should use it. */ | |||
| ret = pipi_create_tile(fmt, plane); | |||
| ret->x = x; | |||
| ret->y = y; | |||
| ret->refcount = 1; | |||
| /* Insert tile and return it. */ | |||
| img->ntiles++; | |||
| img->tiles = realloc(img->tiles, img->ntiles * sizeof(pipi_tile_t *)); | |||
| img->tiles[img->ntiles - 1] = ret; | |||
| return ret; | |||
| } | |||
| void pipi_release_tile(pipi_image_t *img, pipi_tile_t *tile) | |||
| { | |||
| int i; | |||
| for(i = 0; i < img->ntiles; i++) | |||
| { | |||
| if(img->tiles[i] == tile) | |||
| { | |||
| img->tiles[i]->refcount--; | |||
| if(img->tiles[i]->refcount <= 0) | |||
| { | |||
| free(img->tiles[i]); | |||
| img->tiles[i] = img->tiles[img->ntiles - 1]; | |||
| img->ntiles--; | |||
| } | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| pipi_tile_t *pipi_create_tile(pipi_format_t fmt, int plane) | |||
| { | |||
| pipi_tile_t * ret; | |||
| size_t bytes; | |||
| switch(fmt) | |||
| { | |||
| case PIPI_PIXELS_RGBA_U8: | |||
| case PIPI_PIXELS_BGR_U8: | |||
| bytes = sizeof(uint8_t) * TILE_SIZE * TILE_SIZE; | |||
| break; | |||
| case PIPI_PIXELS_RGBA_F32: | |||
| case PIPI_PIXELS_Y_F32: | |||
| bytes = sizeof(float) * TILE_SIZE * TILE_SIZE; | |||
| break; | |||
| default: | |||
| bytes = 0; | |||
| break; | |||
| } | |||
| ret = malloc(sizeof(pipi_tile_t) + bytes); | |||
| ret->fmt = fmt; | |||
| ret->plane = plane; | |||
| ret->data.u8 = ret->align.u8; | |||
| return ret; | |||
| } | |||
| #endif /* USE_TILES */ | |||
| @@ -104,12 +104,20 @@ public: | |||
| /* Image processing */ | |||
| Image AutoContrast() const; | |||
| Image Brightness(float val) const; | |||
| Image Contrast(float val) const; | |||
| Image Convolution(Array2D<float> const &kernel); | |||
| Image Crop(ibox2 box) const; | |||
| Image Dilate(); | |||
| Image Erode(); | |||
| Image Invert() const; | |||
| Image Median(ivec2 radii) const; | |||
| Image Median(Array2D<float> const &kernel) const; | |||
| Image YUVToRGB() const; | |||
| Image Sharpen(Array2D<float> const &kernel); | |||
| Image Threshold(float val) const; | |||
| Image Threshold(vec3 val) const; | |||
| Image RGBToYUV() const; | |||
| Image YUVToRGB() const; | |||
| /* Dithering */ | |||
| Image DitherRandom() const; | |||
| @@ -149,8 +149,9 @@ | |||
| <ClCompile Include="image\codec\zed-palette-image.cpp" /> | |||
| <ClCompile Include="image\color\cie1931.cpp" /> | |||
| <ClCompile Include="image\color\color.cpp" /> | |||
| <ClCompile Include="image\filter\autocontrast.cpp" /> | |||
| <ClCompile Include="image\filter\color.cpp" /> | |||
| <ClCompile Include="image\filter\convolution.cpp" /> | |||
| <ClCompile Include="image\filter\dilate.cpp" /> | |||
| <ClCompile Include="image\filter\median.cpp" /> | |||
| <ClCompile Include="image\filter\yuv.cpp" /> | |||
| <ClCompile Include="image\dither\ediff.cpp" /> | |||
| @@ -364,12 +364,15 @@ | |||
| <ClCompile Include="sys\thread.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="image\filter\autocontrast.cpp"> | |||
| <ClCompile Include="image\filter\color.cpp"> | |||
| <Filter>image\filter</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="image\filter\convolution.cpp"> | |||
| <Filter>image\filter</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="image\filter\dilate.cpp"> | |||
| <Filter>image\filter</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="image\filter\median.cpp"> | |||
| <Filter>image\filter</Filter> | |||
| </ClCompile> | |||