/* * This file is part of the improclib project. * Copyright 2023 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "improclib.h" #include "openmp.h" /** * @brief bin2Im - convert binarized image into uint8t * @param image - binarized image * @param W, H - its size (in pixels!) * @return Image structure */ ilImage *ilbin2Image(const uint8_t *image, int W, int H){ ilImage *ret = ilImage_new(W, H, IMTYPE_U8); int stride = (W + 7) / 8, s1 = (stride*8 == W) ? stride : stride - 1; uint8_t *data = (uint8_t*) ret->data; int rest = W - s1*8; OMP_FOR() for(int y = 0; y < H; y++){ uint8_t *optr = &data[y*W]; const uint8_t *iptr = &image[y*stride]; for(int x = 0; x < s1; x++){ register uint8_t inp = *iptr++; for(int i = 0; i < 8; ++i){ *optr++ = (inp & 0x80) ? 255 : 0; inp <<= 1; } } if(rest){ register uint8_t inp = *iptr; for(int i = 0; i < rest; ++i){ *optr++ = (inp & 0x80) ? 255 : 0; inp <<= 1; } } } ret->minval = 0; ret->maxval = 255; return ret; } /** * Convert image into pseudo-packed (1 char == 8 pixels), all values > bk will be 1, else - 0 * @param im (i) - image to convert * @param stride (o) - new width of image * @param bk - background level (all values < bk will be 0, other will be 1) * @return allocated memory area with "packed" image */ uint8_t *ilImage2bin(const ilImage *im, double bk){ if(!im) return NULL; if(im->type != IMTYPE_U8){ WARNX("ilImage2bin(): supported only 8-bit images"); return NULL; } int W = im->width, H = im->height; if(W < 2 || H < 2) return NULL; int y, W0 = (W + 7) / 8, s1 = (W/8 == W0) ? W0 : W0 - 1; uint8_t *ret = MALLOC(uint8_t, W0 * H); uint8_t *data = (uint8_t*) im->data; int rest = W - s1*8; //OMP_FOR() for(y = 0; y < H; ++y){ uint8_t *iptr = &data[y*W]; uint8_t *optr = &ret[y*W0]; for(int x = 0; x < s1; ++x){ register uint8_t o = 0; for(int i = 0; i < 8; ++i){ o <<= 1; if(*iptr++ > bk) o |= 1; } *optr++ = o; } if(rest){ register uint8_t o = 0; for(int x = 0; x < rest; ++x){ o <<= 1; if(*iptr++ > bk) o |= 1; } *optr = o << (8 - rest); } } return ret; } // transformation functions for Im2u8 #define TRANSMACRO(datatype) \ int height = I->height, width = I->width, stride = width * nchannels; \ uint8_t *outp = MALLOC(uint8_t, height * stride); \ double min = I->minval, max = I->maxval, W = 255./(max - min); \ datatype *Idata = (datatype*) I->data; \ if(nchannels == 3){ \ OMP_FOR() \ for(int y = 0; y < height; ++y){ \ uint8_t *Out = &outp[y*stride]; \ datatype *In = &Idata[y*width]; \ for(int x = 0; x < width; ++x){ \ Out[0] = Out[1] = Out[2] = (uint8_t)(W*((double)(*In++) - min)); \ Out += 3; \ } \ } \ }else{ \ OMP_FOR() \ for(int y = 0; y < height; ++y){ \ uint8_t *Out = &outp[y*stride]; \ datatype *In = &Idata[y*width]; \ for(int x = 0; x < width; ++x){ \ *Out++ = (uint8_t)(W*((double)(*In++) - min)); \ } \ } \ } static uint8_t *Iu8(const ilImage *I, int nchannels){ TRANSMACRO(uint8_t); return outp; } static uint8_t *Iu16(const ilImage *I, int nchannels){ TRANSMACRO(uint16_t); return outp; } static uint8_t *Iu32(const ilImage *I, int nchannels){ TRANSMACRO(uint32_t); return outp; } static uint8_t *If(const ilImage *I, int nchannels){ TRANSMACRO(float); return outp; } static uint8_t *Id(const ilImage *I, int nchannels){ TRANSMACRO(double); return outp; } /** * @brief ilImage2u8 - linear transform for preparing file to save as JPEG or other type * @param I - input image * @param nchannels - 1 or 3 colour channels * @return allocated here image for jpeg/png storing */ uint8_t *ilImage2u8(ilImage *I, int nchannels){ // only 1 and 3 channels supported! if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL; ilImage_minmax(I); //DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels); switch(I->type){ case IMTYPE_U8: return Iu8(I, nchannels); break; case IMTYPE_U16: return Iu16(I, nchannels); break; case IMTYPE_U32: return Iu32(I, nchannels); break; case IMTYPE_F: return If(I, nchannels); break; case IMTYPE_D: return Id(I, nchannels); break; default: WARNX("Im2u8: unsupported image type %d", I->type); } return NULL; } #if 0 UNUSED function! Need to be refactored // convert size_t labels into Image Image *ST2Im(const size_t *image, int W, int H){ Image *ret = Image_new(W, H); OMP_FOR() for(int y = 0; y < H; ++y){ Imtype *optr = &ret->data[y*W]; const size_t *iptr = &image[y*W]; for(int x = 0; x < W; ++x){ *optr++ = (Imtype)*iptr++; } } Image_minmax(ret); return ret; } #endif /** * Convert "packed" image into size_t array for conncomp procedure * @param image (i) - input image * @param W, H - size of image in pixels * @return allocated memory area with copy of an image */ size_t *ilbin2sizet(const uint8_t *image, int W, int H){ size_t *ret = MALLOC(size_t, W * H); int W0 = (W + 7) / 8, s1 = W0 - 1; OMP_FOR() for(int y = 0; y < H; y++){ size_t *optr = &ret[y*W]; const uint8_t *iptr = &image[y*W0]; for(int x = 0; x < s1; ++x){ register uint8_t inp = *iptr++; for(int i = 0; i < 8; ++i){ *optr++ = (inp & 0x80) ? 1 : 0; inp <<= 1; } } int rest = W - s1*8; if(rest){ register uint8_t inp = *iptr; for(int i = 0; i < rest; ++i){ *optr++ = (inp & 0x80) ? 1 : 0; inp <<= 1; } } } return ret; }