sRGBfloat cTexture::BicubicInterpolation(double x, double y, const sRGB8 *bitmap, int w, int h) const { int ix = x; int iy = y; double rx = (x - ix); double ry = (y - iy); double R[4][4], G[4][4], B[4][4]; for(int yy = 0; yy < 4; yy++) { for(int xx = 0; xx < 4; xx++) { int ixx = ix + xx - 1; int iyy = iy + yy - 1; ixx = (ixx + w) % w; iyy = (iyy + h) % h; int addess2 = ixx + iyy * w; sRGB8 pixel = bitmap[addess2]; R[xx][yy] = pixel.R; G[xx][yy] = pixel.G; B[xx][yy] = pixel.B; } } double dR = bicubicInterpolate(R, rx, ry); double dG = bicubicInterpolate(G, rx, ry); double dB = bicubicInterpolate(B, rx, ry); if(dR < 0) dR = 0; if(dR > 255) dR = 255; if(dG < 0) dG = 0; if(dG > 255) dG = 255; if(dB < 0) dB = 0; if(dB > 255) dB = 255; return sRGBfloat(dR/256.0, dG/256.0, dB/256.0); }
// src is a grid src_rows * src_cols // dest is a pre-allocated grid, dest_rows*dest_cols void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, float *dest, uint8_t dest_rows, uint8_t dest_cols) { float mu_x = (src_cols - 1.0) / (dest_cols - 1.0); float mu_y = (src_rows - 1.0) / (dest_rows - 1.0); float adj_2d[16]; // matrix for storing adjacents for (uint8_t y_idx=0; y_idx < dest_rows; y_idx++) { for (uint8_t x_idx=0; x_idx < dest_cols; x_idx++) { float x = x_idx * mu_x; float y = y_idx * mu_y; //Serial.print("("); Serial.print(y_idx); Serial.print(", "); Serial.print(x_idx); Serial.print(") = "); //Serial.print("("); Serial.print(y); Serial.print(", "); Serial.print(x); Serial.print(") = "); get_adjacents_2d(src, adj_2d, src_rows, src_cols, x, y); /* Serial.print("["); for (uint8_t i=0; i<16; i++) { Serial.print(adj_2d[i]); Serial.print(", "); } Serial.println("]"); */ float frac_x = x - (int)x; // we only need the ~delta~ between the points float frac_y = y - (int)y; // we only need the ~delta~ between the points float out = bicubicInterpolate(adj_2d, frac_x, frac_y); //Serial.print("\tInterp: "); Serial.println(out); set_point(dest, dest_rows, dest_cols, x_idx, y_idx, out); } } }
// ray方向からの放射輝度を求める Color radiance(const Ray &ray, const int depth, bool interpolation = true) { double t; // レイからシーンの交差位置までの距離 int id; // 交差したシーン内オブジェクトのID Vec normal; // 交差位置の法線 if (!intersect_scene(ray, &t, &id, &normal)) return BackgroundColor; const Rectangle &obj = recs[id]; const Vec hitpoint = ray.org + t * ray.dir; // 交差位置 // シーンを構成するジオメトリは全て完全拡散面と仮定 switch (DIFFUSE) { case DIFFUSE: { const Vec v = hitpoint - obj.p0; const double a_len = Dot(v, Normalize(obj.a)); const double b_len = Dot(v, Normalize(obj.b)); double da = obj.a_num * a_len / obj.a_len; double db = obj.b_num * b_len / obj.b_len; int ia = int(da); if (ia >= obj.a_num) ia --; int ib = int(db); if (ib >= obj.b_num) ib --; // バイキュービック補間 if (interpolation) { Color c[4][4]; int ia = int(da - 0.5); int ib = int(db - 0.5); for (int i = 0; i < 4; i ++) { for (int j = 0; j < 4; j ++) { c[i][j] = obj.sample(ia + i - 1, ib + j - 1); } } int ia0 = int(da - 0.5); int ib0 = int(db - 0.5); double dx = da - ia0 - 0.5; double dy = db - ib0 - 0.5; if (dx < 0.0) dx = 0.0; if (dx >= 1.0) dx = 1.0; if (dy < 0.0) dy = 0.0; if (dy >= 1.0) dy = 1.0; return PI * bicubicInterpolate(c, dx, dy); } // 完全拡散面なのでPI倍 return PI * obj.patch[ia * obj.b_num + ib]; } break; } }
bool ofPixels_<PixelType>::resizeTo(ofPixels_<PixelType>& dst, ofInterpolationMethod interpMethod) const{ if(&dst == this){ return true; } if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel()) return false; int srcWidth = getWidth(); int srcHeight = getHeight(); int dstWidth = dst.getWidth(); int dstHeight = dst.getHeight(); int bytesPerPixel = getBytesPerPixel(); PixelType * dstPixels = dst.getData(); switch (interpMethod){ //---------------------------------------- case OF_INTERPOLATE_NEAREST_NEIGHBOR:{ int dstIndex = 0; float srcxFactor = (float)srcWidth/dstWidth; float srcyFactor = (float)srcHeight/dstHeight; float srcy = 0.5; for (int dsty=0; dsty<dstHeight; dsty++){ float srcx = 0.5; int srcIndex = int(srcy)*srcWidth; for (int dstx=0; dstx<dstWidth; dstx++){ int pixelIndex = int(srcIndex + srcx) * bytesPerPixel; for (int k=0; k<bytesPerPixel; k++){ dstPixels[dstIndex] = pixels[pixelIndex]; dstIndex++; pixelIndex++; } srcx+=srcxFactor; } srcy+=srcyFactor; } }break; //---------------------------------------- case OF_INTERPOLATE_BILINEAR: // not implemented yet ofLogError("ofPixels") << "resizeTo(): bilinear resize not implemented, not resizing"; break; //---------------------------------------- case OF_INTERPOLATE_BICUBIC: float px1, py1; float px2, py2; float px3, py3; float srcColor = 0; float interpCol; int patchRow; int patchIndex; float patch[16]; int srcRowBytes = srcWidth*bytesPerPixel; int loIndex = (srcRowBytes)+1; int hiIndex = (srcWidth*srcHeight*bytesPerPixel)-(srcRowBytes)-1; for (int dsty=0; dsty<dstHeight; dsty++){ for (int dstx=0; dstx<dstWidth; dstx++){ int dstIndex0 = (dsty*dstWidth + dstx) * bytesPerPixel; float srcxf = srcWidth * (float)dstx/(float)dstWidth; float srcyf = srcHeight * (float)dsty/(float)dstHeight; int srcx = (int) MIN(srcWidth-1, srcxf); int srcy = (int) MIN(srcHeight-1, srcyf); int srcIndex0 = (srcy*srcWidth + srcx) * bytesPerPixel; px1 = srcxf - srcx; py1 = srcyf - srcy; px2 = px1 * px1; px3 = px2 * px1; py2 = py1 * py1; py3 = py2 * py1; for (int k=0; k<bytesPerPixel; k++){ int dstIndex = dstIndex0+k; int srcIndex = srcIndex0+k; for (int dy=0; dy<4; dy++) { patchRow = srcIndex + ((dy-1)*srcRowBytes); for (int dx=0; dx<4; dx++) { patchIndex = patchRow + (dx-1)*bytesPerPixel; if ((patchIndex >= loIndex) && (patchIndex < hiIndex)) { srcColor = pixels[patchIndex]; } patch[dx*4 + dy] = srcColor; } } interpCol = (PixelType)bicubicInterpolate(patch, px1,py1, px2,py2, px3,py3); dstPixels[dstIndex] = interpCol; } } } break; } return true; }
//bool newQuad = false; /// \brief Interpolate the value for point \a x, \a y from the values at the four corners of \a quad double quadInterpolate(qQuadValue quad, double x, double y, bool useBicubic = true) { double w = quad.width(); double h = quad.height(); if(useBicubic) { // Use bicubic impl from http://www.paulinternet.nl/?page=bicubic double unitX = (x - quad.left() ) / w; double unitY = (y - quad.top() ) / h; double c1 = quad.tl.value, c2 = quad.tr.value, c3 = quad.br.value, c4 = quad.bl.value; double p[4][4] = { // {c1,c1,c2,c2}, // {c1,c1,c2,c2}, // {c4,c4,c3,c3}, // {c4,c4,c3,c3} // Note: X runs DOWN, values below are (x1,y1)->(x1,y4), NOT (x1,y1)->(x4,y1) as above (commented out) {c1,c1,c4,c4}, {c1,c1,c4,c4}, {c2,c2,c3,c3}, {c2,c2,c3,c3} }; double p2 = bicubicInterpolate(p, unitX, unitY); //if(p2 > 1.0 || unitX > 1. || unitY > 1. || newQuad) //if(newQuad && unitX > 0.99) //{ //qDebug() << "bicubicInterpolate: unit:"<<unitX<<","<<unitY<<": p2:"<<p2<<", w:"<<w<<", h:"<<h<<", x:"<<x<<", y:"<<y<<", corners:"<<corners[0].point<<corners[1].point<<corners[2].point<<corners[3].point<<", v:"<<c1<<c2<<c3<<c4; //newQuad = false; //} return p2; } else { // Very simple implementation of http://en.wikipedia.org/wiki/Bilinear_interpolation double fr1 = (quad.br.point.x() - x) / w * quad.tl.value + (x - quad.tl.point.x()) / w * quad.tr.value; double fr2 = (quad.br.point.x() - x) / w * quad.bl.value + (x - quad.tl.point.x()) / w * quad.br.value; double h1 = (quad.br.point.y() - y), h2 = (y - quad.tl.point.y()); double p1 = h1 / h * fr1 + h2 / h * fr2; //qDebug() << "quadInterpolate: "<<x<<" x "<<y<<": "<<p1<<" (h1:"<<h1<<", h2:"<<h2<<", fr1:"<<fr1<<",fr2:"<<fr2<<",w:"<<w<<",h:"<<h<<"), bry:"<<quad.br.point.y()<<", tly:"<<quad.tl.point.y(); return p1; } }