/** \file * \brief Image Resize * * See Copyright Notice in im_lib.h * $Id: im_resize.cpp,v 1.2 2010/01/07 19:12:53 scuri Exp $ */ #include #include #include #include #include #include "im_process_loc.h" #include #include static inline void iResizeInverse(int x, int y, float *xl, float *yl, float x_invfactor, float y_invfactor) { *xl = (x + 0.5f) * x_invfactor; *yl = (y + 0.5f) * y_invfactor; } template static int iResize(int src_width, int src_height, const DT *src_map, int dst_width, int dst_height, DT *dst_map, DTU Dummy, int order, int counter) { float xl, yl; float x_invfactor = float(src_width)/float(dst_width); float y_invfactor = float(src_height)/float(dst_height); for (int y = 0; y < dst_height; y++) { for (int x = 0; x < dst_width; x++) { iResizeInverse(x, y, &xl, &yl, x_invfactor, y_invfactor); // if inside the original image if (xl > 0.0 && yl > 0.0 && xl < src_width && yl < src_height) { if (order == 1) *dst_map = imBilinearInterpolation(src_width, src_height, src_map, xl, yl); else if (order == 3) *dst_map = imBicubicInterpolation(src_width, src_height, src_map, xl, yl, Dummy); else *dst_map = imZeroOrderInterpolation(src_width, src_height, src_map, xl, yl); } dst_map++; } if (!imCounterInc(counter)) return 0; } return 1; } template static int iReduce(int src_width, int src_height, const DT *src_map, int dst_width, int dst_height, DT *dst_map, DTU Dummy, int order, int counter) { float xl, yl; float x_invfactor = float(src_width)/float(dst_width); float y_invfactor = float(src_height)/float(dst_height); iResizeInverse(1, 1, &xl, &yl, x_invfactor, y_invfactor); float xl0 = xl, yl0 = yl; iResizeInverse(2, 2, &xl, &yl, x_invfactor, y_invfactor); float xl1 = xl, yl1 = yl; float box_width = xl1 - xl0; float box_height = yl1 - yl0; for (int y = 0; y < dst_height; y++) { for (int x = 0; x < dst_width; x++) { iResizeInverse(x, y, &xl, &yl, x_invfactor, y_invfactor); // if inside the original image if (xl > 0.0 && yl > 0.0 && xl < src_width && yl < src_height) { if (order == 0) *dst_map = imZeroOrderDecimation(src_width, src_height, src_map, xl, yl, box_width, box_height, Dummy); else *dst_map = imBilinearDecimation(src_width, src_height, src_map, xl, yl, box_width, box_height, Dummy); } dst_map++; } if (!imCounterInc(counter)) return 0; } return 1; } int imProcessReduce(const imImage* src_image, imImage* dst_image, int order) { int ret = 0; int counter = imCounterBegin("Reduce Size"); const char* int_msg = (order == 1)? "Bilinear Decimation": "Zero Order Decimation"; int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; imCounterTotal(counter, src_depth*dst_image->height, int_msg); for (int i = 0; i < src_depth; i++) { switch(src_image->data_type) { case IM_BYTE: ret = iReduce(src_image->width, src_image->height, (const imbyte*)src_image->data[i], dst_image->width, dst_image->height, (imbyte*)dst_image->data[i], float(0), order, counter); break; case IM_USHORT: ret = iReduce(src_image->width, src_image->height, (const imushort*)src_image->data[i], dst_image->width, dst_image->height, (imushort*)dst_image->data[i], float(0), order, counter); break; case IM_INT: ret = iReduce(src_image->width, src_image->height, (const int*)src_image->data[i], dst_image->width, dst_image->height, (int*)dst_image->data[i], float(0), order, counter); break; case IM_FLOAT: ret = iReduce(src_image->width, src_image->height, (const float*)src_image->data[i], dst_image->width, dst_image->height, (float*)dst_image->data[i], float(0), order, counter); break; case IM_CFLOAT: ret = iReduce(src_image->width, src_image->height, (const imcfloat*)src_image->data[i], dst_image->width, dst_image->height, (imcfloat*)dst_image->data[i], imcfloat(0,0), order, counter); break; } } imCounterEnd(counter); return ret; } int imProcessResize(const imImage* src_image, imImage* dst_image, int order) { int ret = 0; int counter = imCounterBegin("Resize"); const char* int_msg = (order == 3)? "Bicubic Interpolation": (order == 1)? "Bilinear Interpolation": "Zero Order Interpolation"; int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; imCounterTotal(counter, src_depth*dst_image->height, int_msg); for (int i = 0; i < src_depth; i++) { switch(src_image->data_type) { case IM_BYTE: ret = iResize(src_image->width, src_image->height, (const imbyte*)src_image->data[i], dst_image->width, dst_image->height, (imbyte*)dst_image->data[i], float(0), order, counter); break; case IM_USHORT: ret = iResize(src_image->width, src_image->height, (const imushort*)src_image->data[i], dst_image->width, dst_image->height, (imushort*)dst_image->data[i], float(0), order, counter); break; case IM_INT: ret = iResize(src_image->width, src_image->height, (const int*)src_image->data[i], dst_image->width, dst_image->height, (int*)dst_image->data[i], float(0), order, counter); break; case IM_FLOAT: ret = iResize(src_image->width, src_image->height, (const float*)src_image->data[i], dst_image->width, dst_image->height, (float*)dst_image->data[i], float(0), order, counter); break; case IM_CFLOAT: ret = iResize(src_image->width, src_image->height, (const imcfloat*)src_image->data[i], dst_image->width, dst_image->height, (imcfloat*)dst_image->data[i], imcfloat(0,0), order, counter); break; } } imCounterEnd(counter); return ret; } template static void ReduceBy4(int src_width, int src_height, DT *src_map, int dst_width, int dst_height, DT *dst_map) { int x,y,yd,xd; (void)dst_height; // make an even size int height = (src_height/2)*2; int width = (src_width/2)*2; for(y = 0 ; y < height ; y += 2) { yd = y/2; for(x = 0 ; x < width ; x += 2) { xd = x/2; dst_map[yd * dst_width + xd] = ((src_map[y * src_width + x] + src_map[y * src_width + (x+1)] + src_map[(y+1) * src_width + x] + src_map[(y+1) * src_width + (x+1)])/4); } } } void imProcessReduceBy4(const imImage* src_image, imImage* dst_image) { int i; int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; for (i = 0; i < src_depth; i++) { switch(src_image->data_type) { case IM_BYTE: ReduceBy4(src_image->width, src_image->height, (imbyte*)src_image->data[i], dst_image->width, dst_image->height, (imbyte*)dst_image->data[i]); break; case IM_USHORT: ReduceBy4(src_image->width, src_image->height, (imushort*)src_image->data[i], dst_image->width, dst_image->height, (imushort*)dst_image->data[i]); break; case IM_INT: ReduceBy4(src_image->width, src_image->height, (int*)src_image->data[i], dst_image->width, dst_image->height, (int*)dst_image->data[i]); break; case IM_FLOAT: ReduceBy4(src_image->width, src_image->height, (float*)src_image->data[i], dst_image->width, dst_image->height, (float*)dst_image->data[i]); break; case IM_CFLOAT: ReduceBy4(src_image->width, src_image->height, (imcfloat*)src_image->data[i], dst_image->width, dst_image->height, (imcfloat*)dst_image->data[i]); break; } } } void imProcessCrop(const imImage* src_image, imImage* dst_image, int xmin, int ymin) { int type_size = imDataTypeSize(src_image->data_type); int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; for (int i = 0; i < src_depth; i++) { imbyte *src_map = (imbyte*)src_image->data[i]; imbyte *dst_map = (imbyte*)dst_image->data[i]; for (int y = 0; y < dst_image->height; y++) { int src_offset = (y + ymin)*src_image->line_size + xmin*type_size; int dst_offset = y*dst_image->line_size; memcpy(&dst_map[dst_offset], &src_map[src_offset], dst_image->line_size); } } } void imProcessInsert(const imImage* src_image, const imImage* rgn_image, imImage* dst_image, int xmin, int ymin) { int type_size = imDataTypeSize(src_image->data_type); int dst_size1 = xmin*type_size; int dst_size2 = src_image->line_size - (rgn_image->line_size + dst_size1); int dst_offset2 = dst_size1+rgn_image->line_size; int ymax = ymin+rgn_image->height-1; int rgn_size = rgn_image->line_size; int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; if (dst_size2 < 0) { dst_size2 = 0; rgn_size = src_image->line_size - dst_size1; dst_offset2 = dst_size1+rgn_size; } if (ymax > src_image->height-1) ymax = src_image->height-1; for (int i = 0; i < src_depth; i++) { imbyte *src_map = (imbyte*)src_image->data[i]; imbyte *rgn_map = (imbyte*)rgn_image->data[i]; imbyte *dst_map = (imbyte*)dst_image->data[i]; for (int y = 0; y < src_image->height; y++) { if (y < ymin || y > ymax) { memcpy(dst_map, src_map, src_image->line_size); } else { if (dst_size1) memcpy(dst_map, src_map, dst_size1); memcpy(dst_map + dst_size1, rgn_map, rgn_size); if (dst_size2) memcpy(dst_map + dst_offset2, src_map + dst_offset2, dst_size2); rgn_map += rgn_image->line_size; } src_map += src_image->line_size; dst_map += dst_image->line_size; } } } void imProcessAddMargins(const imImage* src_image, imImage* dst_image, int xmin, int ymin) { int type_size = imDataTypeSize(src_image->data_type); int src_depth = src_image->has_alpha? src_image->depth+1: src_image->depth; for (int i = 0; i < src_depth; i++) { imbyte *dst_map = (imbyte*)dst_image->data[i]; imbyte *src_map = (imbyte*)src_image->data[i]; for (int y = 0; y < src_image->height; y++) { int src_offset = y*src_image->line_size; int dst_offset = (y + ymin)*dst_image->line_size + xmin*type_size; memcpy(&dst_map[dst_offset], &src_map[src_offset], src_image->line_size); } } }