/* * DO NOT EDIT THIS FILE! It was created automatically by m4. */ /* * Copyright (c) 1994 The Board of Trustees of The Leland Stanford * Junior University. All rights reserved. * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice and this permission notice appear in * all copies of this software and that you do not sell the software. * Commercial licensing is available by contacting the author. * * THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * Author: * Phil Lacroute * Computer Systems Laboratory * Electrical Engineering Dept. * Stanford University */ /* * vp_warpA.m4 * * One-pass image warping routine for affine transformations. * * Copyright (c) 1994 The Board of Trustees of The Leland Stanford * Junior University. All rights reserved. * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice and this permission notice appear in * all copies of this software and that you do not sell the software. * Commercial licensing is available by contacting the author. * * THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * Author: * Phil Lacroute * Computer Systems Laboratory * Electrical Engineering Dept. * Stanford University */ /* * $Date$ * $Revision$ */ #include "vp_global.h" /* convert a float in the interval [0-1) to a 31-bit fixed point */ #define FLTFRAC_TO_FIX31(f) ((int)((f) * 2147483648.)) /* convert a 31-bit fixed point to a weight table index */ #define FIX31_TO_WGTIND(f) ((f) >> (31 - WARP_WEIGHT_INDEX_BITS)) extern float VPBilirpWeight[WARP_WEIGHT_ENTRIES][WARP_WEIGHT_ENTRIES][4]; /* * VPWarpA330R * * One-pass warper. Transforms in_image to out_image according to * the affine warp specified by warp_matrix. The resampling filter * is a bilirp (suitable for upsampling only). */ void VPWarpA330R (in_image, in_width, in_height, in_bytes_per_scan, out_image, out_width, out_height, out_bytes_per_scan, warp_matrix) RGBIntPixel *in_image; /* input image data */ int in_width; /* size of input image */ int in_height; int in_bytes_per_scan; /* bytes per scanline in input image */ char *out_image; /* output image data */ int out_width; /* size of output image */ int out_height; int out_bytes_per_scan; /* bytes per scanline in output image */ vpMatrix3 warp_matrix; /* [ outx ] [ inx ] */ /* [ outy ] = warp_matrix * [ iny ] */ /* [ 1 ] [ 1 ] */ { Trapezoid full_overlap[9]; /* description of the area of overlap of output image (shrunk by the size of the filter kernel) with input image */ Trapezoid part_overlap[9]; /* description of the area of overlap of output image (unlarged by the size of the filter kernel) with input image */ int region; /* index into full/part_overlap */ char *out_ptr; /* pointer to current pixel of output image */ int out_scan_y; /* coordinate of current output scanline */ int scans_to_next_vertex; /* number of scans left to process before the next vertex is reached */ RGBIntPixel *in_ptr; /* pointer to current pixel of input image */ double x_lft_full, x_rgt_full; /* intersection of scan with full_overlap */ double x_lft_part, x_rgt_part; /* intersection of scan with part_overlap */ int no_full_pixels; /* true if full_overlap is empty for scan */ double in_x, in_y; /* exact coordinates in the input image of the current output image pixel */ int in_x_int, in_y_int; /* coordinates of the nearest input image pixel to the upper-left of the current output image pixel */ int xfrac, yfrac; /* in_x - in_x_int and in_y - in_y_int, stored as a fixed-point number with 31 bits of fraction */ int xfrac_incr, yfrac_incr; /* increments to xfrac and yfrac to give the fractions for the next output image pixel in the current scan */ double in_x_incr, in_y_incr;/* increments to in_x and in_y to give the input image coordinates of the next output image pixel in the current scan (equal to dx_in/dx_out and dy_in/dx_out) */ int in_x_incr_int, in_y_incr_int; /* integer part of in_x/y_incr */ int in_x_incr_dlt, in_y_incr_dlt; /* sign of in_x/y_incr */ float *wptr; /* pointer into weight table */ int lft_zero_cnt; /* # zero pixels on left edge of scan */ int lft_edge_cnt; /* # pixels on left w/ part filter overlap */ int full_cnt; /* # pixels w/ full filter overlap */ int rgt_edge_cnt; /* # pixels on rgt w/ part filter overlap */ int rgt_zero_cnt; /* # zero pixels on right edge of scan */ int x; /* pixel index */ float r_acc, g_acc, b_acc; int r_acc_int, g_acc_int, b_acc_int; /* pixel accumulator */ double denom; int c; #ifdef DEBUG { int y; for (y = 0; y < out_height; y++) { out_ptr = out_image + y*out_bytes_per_scan; for (x = 0; x < out_width; x++) { for (c = 0; c < ((3) + (0)); c++) *out_ptr++ = 255; } } } #endif /* initialize tables */ VPComputeWarpTables(); /* compute the intersection of the input image and the output image */ /* filter width = 2.0 in input image space (triangle filter) */ VPAffineImageOverlap(in_width, in_height, out_width, out_height, warp_matrix, 2., full_overlap, part_overlap); /* compute the output image */ out_ptr = out_image; out_scan_y = 0; denom = 1. / (warp_matrix[0][0] * warp_matrix[1][1] - warp_matrix[0][1] * warp_matrix[1][0]); in_x_incr = warp_matrix[1][1]*denom; in_y_incr = -warp_matrix[1][0]*denom; if (in_x_incr < 0) { in_x_incr_int = (int)ceil(in_x_incr); in_x_incr_dlt = -1; } else { in_x_incr_int = (int)floor(in_x_incr); in_x_incr_dlt = 1; } if (in_y_incr < 0) { in_y_incr_int = (int)ceil(in_y_incr); in_y_incr_dlt = -1; } else { in_y_incr_int = (int)floor(in_y_incr); in_y_incr_dlt = 1; } xfrac_incr = FLTFRAC_TO_FIX31(in_x_incr - in_x_incr_int); yfrac_incr = FLTFRAC_TO_FIX31(in_y_incr - in_y_incr_int); for (region = 0; region < 9; region++) { /* check for empty region */ if (part_overlap[region].miny >= out_height) { break; } /* check if this region of the output image is unaffected by the input image */ if (part_overlap[region].x_top_lft > part_overlap[region].x_top_rgt) { c = (part_overlap[region].maxy - part_overlap[region].miny + 1) * out_bytes_per_scan; bzero(out_ptr, c); out_ptr += c; out_scan_y += part_overlap[region].maxy - part_overlap[region].miny + 1; continue; } /* process scanlines of this region */ scans_to_next_vertex = part_overlap[region].maxy - part_overlap[region].miny + 1; x_lft_full = full_overlap[region].x_top_lft; x_rgt_full = full_overlap[region].x_top_rgt; x_lft_part = part_overlap[region].x_top_lft; x_rgt_part = part_overlap[region].x_top_rgt; if (x_lft_full > x_rgt_full) no_full_pixels = 1; else no_full_pixels = 0; ASSERT(scans_to_next_vertex > 0); ASSERT(out_scan_y == part_overlap[region].miny); while (scans_to_next_vertex > 0) { /* compute the portions of the scanline which are zero and which intersect the full and partially-full regions */ lft_zero_cnt = (int)floor(x_lft_part); if (lft_zero_cnt < 0) lft_zero_cnt = 0; else if (lft_zero_cnt > out_width) lft_zero_cnt = out_width; if (no_full_pixels) { lft_edge_cnt = (int)ceil(x_rgt_part); if (lft_edge_cnt < 0) lft_edge_cnt = 0; else if (lft_edge_cnt > out_width) lft_edge_cnt = out_width; lft_edge_cnt -= lft_zero_cnt; if (lft_edge_cnt < 0) lft_edge_cnt = 0; full_cnt = 0; rgt_edge_cnt = 0; rgt_zero_cnt = out_width - lft_zero_cnt - lft_edge_cnt; } else { lft_edge_cnt = (int)ceil(x_lft_full); if (lft_edge_cnt < 0) lft_edge_cnt = 0; else if (lft_edge_cnt > out_width) lft_edge_cnt = out_width; lft_edge_cnt -= lft_zero_cnt; if (lft_edge_cnt < 0) lft_edge_cnt = 0; full_cnt = (int)floor(x_rgt_full); if (full_cnt < 0) full_cnt = 0; else if (full_cnt > out_width) full_cnt = out_width; full_cnt -= lft_edge_cnt + lft_zero_cnt; if (full_cnt < 0) full_cnt = 0; rgt_edge_cnt = (int)ceil(x_rgt_part); if (rgt_edge_cnt < 0) rgt_edge_cnt = 0; else if (rgt_edge_cnt > out_width) rgt_edge_cnt = out_width; rgt_edge_cnt -= full_cnt + lft_edge_cnt + lft_zero_cnt; if (rgt_edge_cnt < 0) rgt_edge_cnt = 0; rgt_zero_cnt = out_width - lft_zero_cnt - lft_edge_cnt - full_cnt - rgt_edge_cnt; } /* reverse map the first left-edge output pixel coordinate into the input image coordinate system */ in_x = ((lft_zero_cnt - warp_matrix[0][2]) * warp_matrix[1][1] - (out_scan_y - warp_matrix[1][2])*warp_matrix[0][1])*denom; in_y = (-(lft_zero_cnt - warp_matrix[0][2]) * warp_matrix[1][0] + (out_scan_y - warp_matrix[1][2])*warp_matrix[0][0])*denom; in_x_int = (int)floor(in_x); in_y_int = (int)floor(in_y); in_ptr = (RGBIntPixel *)(((char *)in_image + in_y_int * in_bytes_per_scan)) + in_x_int; /* compute the weight lookup table indices and increments */ xfrac = FLTFRAC_TO_FIX31(in_x - in_x_int); yfrac = FLTFRAC_TO_FIX31(in_y - in_y_int); /* zero out unaffected pixels on left edge of scan */ if (lft_zero_cnt > 0) { bzero(out_ptr, lft_zero_cnt * ((3) + (0))); out_ptr += lft_zero_cnt * ((3) + (0)); } /* process left edge case pixels */ for (x = lft_zero_cnt; x < lft_zero_cnt + lft_edge_cnt; x++) { wptr = VPBilirpWeight[FIX31_TO_WGTIND(yfrac)] [FIX31_TO_WGTIND(xfrac)]; r_acc = g_acc = b_acc = 0; ; if (in_x_int >= 0 && in_x_int < in_width) { if (in_y_int >= 0 && in_y_int < in_height) { r_acc += (wptr[0]) * (in_ptr[0].rclrflt); g_acc += (wptr[0]) * (in_ptr[0].gclrflt); b_acc += (wptr[0]) * (in_ptr[0].bclrflt); ; } if (in_y_int+1 >= 0 && in_y_int+1 < in_height) { r_acc += (wptr[2]) * (in_ptr[in_width].rclrflt); g_acc += (wptr[2]) * (in_ptr[in_width].gclrflt); b_acc += (wptr[2]) * (in_ptr[in_width].bclrflt); ; } } if (in_x_int+1 >= 0 && in_x_int+1 < in_width) { if (in_y_int >= 0 && in_y_int < in_height) { r_acc += (wptr[1]) * (in_ptr[1].rclrflt); g_acc += (wptr[1]) * (in_ptr[1].gclrflt); b_acc += (wptr[1]) * (in_ptr[1].bclrflt); ; } if (in_y_int+1 >= 0 && in_y_int+1 < in_height) { r_acc += (wptr[3]) * (in_ptr[in_width + 1].rclrflt); g_acc += (wptr[3]) * (in_ptr[in_width + 1].gclrflt); b_acc += (wptr[3]) * (in_ptr[in_width + 1].bclrflt); ; } } r_acc_int = r_acc; if (r_acc_int > 255) r_acc_int = 255; ((out_ptr)[0+2]) = r_acc_int; g_acc_int = g_acc; if (g_acc_int > 255) g_acc_int = 255; ((out_ptr)[0+1]) = g_acc_int; b_acc_int = b_acc; if (b_acc_int > 255) b_acc_int = 255; ((out_ptr)[0+0]) = b_acc_int;; out_ptr += ((3) + (0)); xfrac += xfrac_incr; yfrac += yfrac_incr; if (xfrac < 0) { xfrac &= 0x7fffffff; in_x_int += in_x_incr_int + in_x_incr_dlt; in_ptr += in_x_incr_int + in_x_incr_dlt; } else { in_x_int += in_x_incr_int; in_ptr += in_x_incr_int; } if (yfrac < 0) { yfrac &= 0x7fffffff; in_y_int += in_y_incr_int + in_y_incr_dlt; in_ptr += in_width * (in_y_incr_int + in_y_incr_dlt); } else { in_y_int += in_y_incr_int; in_ptr += in_width * in_y_incr_int; } } /* process output pixels affected by four input pixels */ for (x = lft_zero_cnt + lft_edge_cnt; x < lft_zero_cnt + lft_edge_cnt + full_cnt; x++) { ASSERT(in_x_int >= 0 && in_x_int < in_width-1); ASSERT(in_y_int >= 0 && in_y_int < in_height-1); ASSERT((RGBIntPixel *)(((char *)in_image + in_y_int * in_bytes_per_scan)) + in_x_int == in_ptr); wptr = VPBilirpWeight[FIX31_TO_WGTIND(yfrac)] [FIX31_TO_WGTIND(xfrac)]; r_acc = (wptr[0]) * (in_ptr[0].rclrflt) + (wptr[2]) * (in_ptr[in_width].rclrflt) + (wptr[1]) * (in_ptr[1].rclrflt) + (wptr[3]) * (in_ptr[in_width+1].rclrflt); g_acc = (wptr[0]) * (in_ptr[0].gclrflt) + (wptr[2]) * (in_ptr[in_width].gclrflt) + (wptr[1]) * (in_ptr[1].gclrflt) + (wptr[3]) * (in_ptr[in_width+1].gclrflt); b_acc = (wptr[0]) * (in_ptr[0].bclrflt) + (wptr[2]) * (in_ptr[in_width].bclrflt) + (wptr[1]) * (in_ptr[1].bclrflt) + (wptr[3]) * (in_ptr[in_width+1].bclrflt); ; r_acc_int = r_acc; if (r_acc_int > 255) r_acc_int = 255; ((out_ptr)[0+2]) = r_acc_int; g_acc_int = g_acc; if (g_acc_int > 255) g_acc_int = 255; ((out_ptr)[0+1]) = g_acc_int; b_acc_int = b_acc; if (b_acc_int > 255) b_acc_int = 255; ((out_ptr)[0+0]) = b_acc_int;; out_ptr += ((3) + (0)); xfrac += xfrac_incr; yfrac += yfrac_incr; if (xfrac < 0) { xfrac &= 0x7fffffff; in_x_int += in_x_incr_int + in_x_incr_dlt; in_ptr += in_x_incr_int + in_x_incr_dlt; } else { in_x_int += in_x_incr_int; in_ptr += in_x_incr_int; } if (yfrac < 0) { yfrac &= 0x7fffffff; in_y_int += in_y_incr_int + in_y_incr_dlt; in_ptr += in_width * (in_y_incr_int + in_y_incr_dlt); } else { in_y_int += in_y_incr_int; in_ptr += in_width * in_y_incr_int; } } /* process right edge case pixels */ for (x = lft_zero_cnt + lft_edge_cnt + full_cnt; x < lft_zero_cnt + lft_edge_cnt + full_cnt + rgt_edge_cnt; x++) { wptr = VPBilirpWeight[FIX31_TO_WGTIND(yfrac)] [FIX31_TO_WGTIND(xfrac)]; r_acc = g_acc = b_acc = 0; ; if (in_x_int >= 0 && in_x_int < in_width) { if (in_y_int >= 0 && in_y_int < in_height) { r_acc += (wptr[0]) * (in_ptr[0].rclrflt); g_acc += (wptr[0]) * (in_ptr[0].gclrflt); b_acc += (wptr[0]) * (in_ptr[0].bclrflt); ; } if (in_y_int+1 >= 0 && in_y_int+1 < in_height) { r_acc += (wptr[2]) * (in_ptr[in_width].rclrflt); g_acc += (wptr[2]) * (in_ptr[in_width].gclrflt); b_acc += (wptr[2]) * (in_ptr[in_width].bclrflt); ; } } if (in_x_int+1 >= 0 && in_x_int+1 < in_width) { if (in_y_int >= 0 && in_y_int < in_height) { r_acc += (wptr[1]) * (in_ptr[1].rclrflt); g_acc += (wptr[1]) * (in_ptr[1].gclrflt); b_acc += (wptr[1]) * (in_ptr[1].bclrflt); ; } if (in_y_int+1 >= 0 && in_y_int+1 < in_height) { r_acc += (wptr[3]) * (in_ptr[in_width + 1].rclrflt); g_acc += (wptr[3]) * (in_ptr[in_width + 1].gclrflt); b_acc += (wptr[3]) * (in_ptr[in_width + 1].bclrflt); ; } } r_acc_int = r_acc; if (r_acc_int > 255) r_acc_int = 255; ((out_ptr)[0+2]) = r_acc_int; g_acc_int = g_acc; if (g_acc_int > 255) g_acc_int = 255; ((out_ptr)[0+1]) = g_acc_int; b_acc_int = b_acc; if (b_acc_int > 255) b_acc_int = 255; ((out_ptr)[0+0]) = b_acc_int;; out_ptr += ((3) + (0)); xfrac += xfrac_incr; yfrac += yfrac_incr; if (xfrac < 0) { xfrac &= 0x7fffffff; in_x_int += in_x_incr_int + in_x_incr_dlt; in_ptr += in_x_incr_int + in_x_incr_dlt; } else { in_x_int += in_x_incr_int; in_ptr += in_x_incr_int; } if (yfrac < 0) { yfrac &= 0x7fffffff; in_y_int += in_y_incr_int + in_y_incr_dlt; in_ptr += in_width * (in_y_incr_int + in_y_incr_dlt); } else { in_y_int += in_y_incr_int; in_ptr += in_width * in_y_incr_int; } } /* zero out unaffected pixels on right edge of scan */ if (rgt_zero_cnt > 0) { bzero(out_ptr, rgt_zero_cnt * ((3) + (0))); out_ptr += rgt_zero_cnt * ((3) + (0)); } /* go on to next scan */ scans_to_next_vertex--; out_scan_y++; out_ptr += out_bytes_per_scan - out_width * ((3) + (0)); x_lft_full += full_overlap[region].x_incr_lft; x_rgt_full += full_overlap[region].x_incr_rgt; x_lft_part += part_overlap[region].x_incr_lft; x_rgt_part += part_overlap[region].x_incr_rgt; } /* next scanline in region */ } /* next region */ ASSERT(out_scan_y == out_height); }