/* -*- mode: c++; c-basic-offset: 4 -*- */ /* image.h * */ #ifndef _IMAGE_H #define _IMAGE_H #include <vector> // utilities for irregular grids void _bin_indices_middle( unsigned int *irows, int nrows, const float *ys1, unsigned long ny, float dy, float y_min); void _bin_indices_middle_linear(float *arows, unsigned int *irows, int nrows, const float *y, unsigned long ny, float dy, float y_min); void _bin_indices(int *irows, int nrows, const double *y, unsigned long ny, double sc, double offs); void _bin_indices_linear( float *arows, int *irows, int nrows, double *y, unsigned long ny, double sc, double offs); template <class CoordinateArray, class ColorArray, class OutputArray> void pcolor(CoordinateArray &x, CoordinateArray &y, ColorArray &d, unsigned int rows, unsigned int cols, float bounds[4], int interpolation, OutputArray &out) { if (rows >= 32768 || cols >= 32768) { throw std::runtime_error("rows and cols must both be less than 32768"); } float x_min = bounds[0]; float x_max = bounds[1]; float y_min = bounds[2]; float y_max = bounds[3]; float width = x_max - x_min; float height = y_max - y_min; float dx = width / ((float)cols); float dy = height / ((float)rows); // Check we have something to output to if (rows == 0 || cols == 0) { throw std::runtime_error("Cannot scale to zero size"); } if (d.dim(2) != 4) { throw std::runtime_error("data must be in RGBA format"); } // Check dimensions match unsigned long nx = x.dim(0); unsigned long ny = y.dim(0); if (nx != (unsigned long)d.dim(1) || ny != (unsigned long)d.dim(0)) { throw std::runtime_error("data and axis dimensions do not match"); } // Allocate memory for pointer arrays std::vector<unsigned int> rowstarts(rows); std::vector<unsigned int> colstarts(cols); // Calculate the pointer arrays to map input x to output x unsigned int i, j; unsigned int *colstart = &colstarts[0]; unsigned int *rowstart = &rowstarts[0]; const float *xs1 = x.data(); const float *ys1 = y.data(); // Copy data to output buffer const unsigned char *start; const unsigned char *inposition; size_t inrowsize = nx * 4; size_t rowsize = cols * 4; unsigned char *position = (unsigned char *)out.data(); unsigned char *oldposition = NULL; start = d.data(); if (interpolation == NEAREST) { _bin_indices_middle(colstart, cols, xs1, nx, dx, x_min); _bin_indices_middle(rowstart, rows, ys1, ny, dy, y_min); for (i = 0; i < rows; i++, rowstart++) { if (i > 0 && *rowstart == 0) { memcpy(position, oldposition, rowsize * sizeof(unsigned char)); oldposition = position; position += rowsize; } else { oldposition = position; start += *rowstart * inrowsize; inposition = start; for (j = 0, colstart = &colstarts[0]; j < cols; j++, position += 4, colstart++) { inposition += *colstart * 4; memcpy(position, inposition, 4 * sizeof(unsigned char)); } } } } else if (interpolation == BILINEAR) { std::vector<float> acols(cols); std::vector<float> arows(rows); _bin_indices_middle_linear(&acols[0], colstart, cols, xs1, nx, dx, x_min); _bin_indices_middle_linear(&arows[0], rowstart, rows, ys1, ny, dy, y_min); double a00, a01, a10, a11, alpha, beta; // Copy data to output buffer for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { alpha = arows[i]; beta = acols[j]; a00 = alpha * beta; a01 = alpha * (1.0 - beta); a10 = (1.0 - alpha) * beta; a11 = 1.0 - a00 - a01 - a10; for (size_t k = 0; k < 4; ++k) { position[k] = d(rowstart[i], colstart[j], k) * a00 + d(rowstart[i], colstart[j] + 1, k) * a01 + d(rowstart[i] + 1, colstart[j], k) * a10 + d(rowstart[i] + 1, colstart[j] + 1, k) * a11; } position += 4; } } } } template <class CoordinateArray, class ColorArray, class Color, class OutputArray> void pcolor2(CoordinateArray &x, CoordinateArray &y, ColorArray &d, unsigned int rows, unsigned int cols, float bounds[4], Color &bg, OutputArray &out) { double x_left = bounds[0]; double x_right = bounds[1]; double y_bot = bounds[2]; double y_top = bounds[3]; // Check we have something to output to if (rows == 0 || cols == 0) { throw std::runtime_error("rows or cols is zero; there are no pixels"); } if (d.dim(2) != 4) { throw std::runtime_error("data must be in RGBA format"); } // Check dimensions match unsigned long nx = x.dim(0); unsigned long ny = y.dim(0); if (nx != (unsigned long)d.dim(1) + 1 || ny != (unsigned long)d.dim(0) + 1) { throw std::runtime_error("data and axis bin boundary dimensions are incompatible"); } if (bg.dim(0) != 4) { throw std::runtime_error("bg must be in RGBA format"); } std::vector<int> irows(rows); std::vector<int> jcols(cols); // Calculate the pointer arrays to map input x to output x size_t i, j; const double *x0 = x.data(); const double *y0 = y.data(); double sx = cols / (x_right - x_left); double sy = rows / (y_top - y_bot); _bin_indices(&jcols[0], cols, x0, nx, sx, x_left); _bin_indices(&irows[0], rows, y0, ny, sy, y_bot); // Copy data to output buffer unsigned char *position = (unsigned char *)out.data(); for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { if (irows[i] == -1 || jcols[j] == -1) { memcpy(position, (const unsigned char *)bg.data(), 4 * sizeof(unsigned char)); } else { for (size_t k = 0; k < 4; ++k) { position[k] = d(irows[i], jcols[j], k); } } position += 4; } } } #endif