cv::Mat flowToColor(const cv::Mat & flow, float max) { assert(flow.channels() == 2); int rows = flow.rows; int cols = flow.cols; CFloatImage cFlow(cols, rows, 2); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cFlow.Pixel(j, i, 0) = flow.at<cv::Vec2f>(i, j)[0]; cFlow.Pixel(j, i, 1) = flow.at<cv::Vec2f>(i, j)[1]; } } CByteImage cImage; MotionToColor(cFlow, cImage, max); assert(cImage.Shape().height == rows); assert(cImage.Shape().width == cols); assert(cImage.Shape().nBands == 3); cv::Mat image(rows, cols, CV_8UC3, cv::Scalar(0, 0, 0)); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { image.at<cv::Vec3b>(i, j)[0] = cImage.Pixel(j, i, 0); image.at<cv::Vec3b>(i, j)[1] = cImage.Pixel(j, i, 1); image.at<cv::Vec3b>(i, j)[2] = cImage.Pixel(j, i, 2); } } return image; }
/******************* TO DO 5 ********************* * NormalizeBlend: * INPUT: * acc: input image whose alpha channel (4th channel) contains * normalizing weight values * img: where output image will be stored * OUTPUT: * normalize r,g,b values (first 3 channels) of acc and store it into img */ static void NormalizeBlend(CFloatImage& acc, CByteImage& img) { // *** BEGIN TODO *** // fill in this routine.. int width = acc.Shape().width; int height = acc.Shape().height; for (int i=0;i<width;i++){ for (int j=0;j<height;j++){ float w = acc.Pixel(i,j,3); img.Pixel(i,j,3) = 255; if (w > 0){ img.Pixel(i,j,0) = acc.Pixel(i,j,0) / w; img.Pixel(i,j,1) = acc.Pixel(i,j,1) / w; img.Pixel(i,j,2) = acc.Pixel(i,j,2) / w; } else { img.Pixel(i,j,0) = 0; img.Pixel(i,j,1) = 0; img.Pixel(i,j,2) = 0; } } } // *** END TODO *** }
// convert float disparity image into a color image using jet colormap void float2color(CFloatImage fimg, CByteImage &img, float dmin, float dmax) { CShape sh = fimg.Shape(); int width = sh.width, height = sh.height; sh.nBands = 3; img.ReAllocate(sh); float scale = 1.0 / (dmax - dmin); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float f = fimg.Pixel(x, y, 0); int r = 0; int g = 0; int b = 0; if (f != INFINITY) { float val = scale * (f - dmin); jet(val, r, g, b); } img.Pixel(x, y, 0) = b; img.Pixel(x, y, 1) = g; img.Pixel(x, y, 2) = r; } } }
/******************* TO DO 5 ********************* * NormalizeBlend: * INPUT: * acc: input image whose alpha channel (4th channel) contains * normalizing weight values * img: where output image will be stored * OUTPUT: * normalize r,g,b values (first 3 channels) of acc and store it into img */ static void NormalizeBlend(CFloatImage& acc, CByteImage& img) { // BEGIN TODO // fill in this routine.. // divide the total weight for every pixel CShape shacc=acc.Shape(); int widthacc=shacc.width; int heightacc=shacc.height; for (int ii=0;ii<widthacc;ii++) { for (int jj=0;jj<heightacc;jj++) { if (acc.Pixel(ii,jj,3)>0) { img.Pixel(ii,jj,0)=(int)(acc.Pixel(ii,jj,0)/acc.Pixel(ii,jj,3)); img.Pixel(ii,jj,1)=(int)(acc.Pixel(ii,jj,1)/acc.Pixel(ii,jj,3)); img.Pixel(ii,jj,2)=(int)(acc.Pixel(ii,jj,2)/acc.Pixel(ii,jj,3)); } else { img.Pixel(ii,jj,0)=0; img.Pixel(ii,jj,1)=0; img.Pixel(ii,jj,2)=0; } } } // END TODO }
// Flip the y-axis of an image void FlipImage(CByteImage &imageIn, CByteImage &imageOut) { CShape sh = imageIn.Shape(); assert(imageIn.Shape().nBands == imageIn.Shape().nBands); for (int y=0; y<sh.height; y++) { for (int x=0; x<sh.width; x++) { for (int c=0; c<sh.nBands; c++) { imageOut.Pixel(x,sh.height-y-1,c) = imageIn.Pixel(x,y,c); } } } }
void convertToFloatImage(CByteImage &byteImage, CFloatImage &floatImage) { CShape sh = byteImage.Shape(); //printf("%d\n", floatImage.Shape().nBands); //printf("%d\n", byteImage.Shape().nBands); assert(floatImage.Shape().nBands == min(byteImage.Shape().nBands, 3)); for (int y=0; y<sh.height; y++) { for (int x=0; x<sh.width; x++) { for (int c=0; c<min(3,sh.nBands); c++) { float value = byteImage.Pixel(x,y,c) / 255.0f; if (value < floatImage.MinVal()) { value = floatImage.MinVal(); } else if (value > floatImage.MaxVal()) { value = floatImage.MaxVal(); } // We have to flip the image and reverse the color // channels to get it to come out right. How silly! floatImage.Pixel(x,sh.height-y-1,min(3,sh.nBands)-c-1) = value; } } } }
//Loop through the image to determine suitable feature points // srcImage: image with Harris values // destImage: Assign 1 to local maximum in 3x3 window that are above a given // threshold, 0 otherwise void computeLocalMaxima(CFloatImage &srcImage,CByteImage &destImage) { int w = srcImage.Shape().width; // image width int h = srcImage.Shape().height; // image height //float threshold = .024; float threshold = .01; // threshold value for identifying features // Declare additional variables float max; // harris value to check as local max int newX, newY; // (x,y) coordinate for pixel in 5x5 sliding window int j; // int for iterating through 5x5 window // Loop through 'srcImage' and determine suitable feature points that // fit the following criteria: // - harris value c is greater than a predefined threshold // - c is a local maximum in a 5x5 neighborhood for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { max = srcImage.Pixel(x,y,0); // If harris value is greater than a predefined threshold check // if value is a local maximum in a 5x5 neighborhood. if (max > threshold) { for (j = 0; j < 25; j++) { find5x5Index(x,y,j,&newX,&newY); if(srcImage.Shape().InBounds(newX, newY) && srcImage.Pixel(newX, newY, 0) > max) { destImage.Pixel(x,y,0) = 0; break; } } if (j != 25) continue; destImage.Pixel(x,y,0) = 1; } else { destImage.Pixel(x,y,0) = 0; } } } }
// Convert Fl_Image to CFloatImage. bool convertImage(const Fl_Image *image, CByteImage &convertedImage) { if (image == NULL) { return false; } // Let's not handle indexed color images. if (image->count() != 1) { return false; } int w = image->w(); int h = image->h(); int d = image->d(); // Get the image data. const char *const *data = image->data(); int index = 0; for (int y=0; y<h; y++) { for (int x=0; x<w; x++) { if (d < 3) { // If there are fewer than 3 channels, just use the // first one for all colors. convertedImage.Pixel(x,y,0) = data[0][index]; convertedImage.Pixel(x,y,1) = data[0][index]; convertedImage.Pixel(x,y,2) = data[0][index]; } else if (d == 3) { // Otherwise, use the first 3. convertedImage.Pixel(x,h-y-1,2) = data[0][index]; convertedImage.Pixel(x,h-y-1,1) = data[0][index+1]; convertedImage.Pixel(x,h-y-1,0) = data[0][index+2]; } index += d; } } return true; }
void getDisparities(MRF *mrf, int width, int height, CByteImage &disp) { CShape sh(width, height, 1); disp.ReAllocate(sh); int n = 0; for (int y = 0; y < height; y++) { uchar *row = &disp.Pixel(0, y, 0); for (int x = 0; x < width; x++) { row[x] = mrf->getLabel(n++); } } }
void setDisparities(CByteImage disp, MRF *mrf) { CShape sh = disp.Shape(); int width = sh.width, height = sh.height; int n = 0; for (int y = 0; y < height; y++) { uchar *row = &disp.Pixel(0, y, 0); for (int x = 0; x < width; x++) { mrf->setLabel(n++, row[x]); } } }
void computeCues(CByteImage im1, MRF::CostVal *&hCue, MRF::CostVal *&vCue, int gradThresh, int gradPenalty) { CShape sh = im1.Shape(); int width = sh.width, height = sh.height, nB = sh.nBands; hCue = new MRF::CostVal[width * height]; vCue = new MRF::CostVal[width * height]; int nColors = __min(3, nB); // below we compute sum of squared colordiffs, so need to adjust threshold accordingly (results in RMS) gradThresh *= nColors * gradThresh; //sh.nBands=1; //CByteImage hc(sh), vc(sh); int n = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uchar *pix = &im1.Pixel(x, y, 0); uchar *pix1x = &im1.Pixel(x + (x < width-1), y, 0); uchar *pix1y = &im1.Pixel(x, y + (y < height-1), 0); int sx = 0, sy = 0; for (int b = 0; b < nColors; b++) { int dx = pix[b] - pix1x[b]; int dy = pix[b] - pix1y[b]; sx += dx * dx; sy += dy * dy; } hCue[n] = (sx < gradThresh ? gradPenalty : 1); vCue[n] = (sy < gradThresh ? gradPenalty : 1); //hc.Pixel(x, y, 0) = 100*hCue[n]; //vc.Pixel(x, y, 0) = 100*vCue[n]; n++; } } //WriteImageVerb(hc, "hcue.png", true); //WriteImageVerb(vc, "vcue.png", true); //exit(1); }
void MotionToColor(CFloatImage motim, CByteImage &colim, float maxmotion) { CShape sh = motim.Shape(); int width = sh.width, height = sh.height; colim.ReAllocate(CShape(width, height, 3)); int x, y; // determine motion range: float maxx = -999, maxy = -999; float minx = 999, miny = 999; float maxrad = -1; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { float fx = motim.Pixel(x, y, 0); float fy = motim.Pixel(x, y, 1); if (unknown_flow(fx, fy)) continue; maxx = __max(maxx, fx); maxy = __max(maxy, fy); minx = __min(minx, fx); miny = __min(miny, fy); float rad = sqrt(fx * fx + fy * fy); maxrad = __max(maxrad, rad); } } printf("max motion: %.4f motion range: u = %.3f .. %.3f; v = %.3f .. %.3f\n", maxrad, minx, maxx, miny, maxy); if (maxmotion > 0) // i.e., specified on commandline maxrad = maxmotion; if (maxrad == 0) // if flow == 0 everywhere maxrad = 1; if (verbose) fprintf(stderr, "normalizing by %g\n", maxrad); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { float fx = motim.Pixel(x, y, 0); float fy = motim.Pixel(x, y, 1); uchar *pix = &colim.Pixel(x, y, 0); if (unknown_flow(fx, fy)) { pix[0] = pix[1] = pix[2] = 0; } else { computeColor(fx/maxrad, fy/maxrad, pix); } } } }
void makeNonoccMask(CFloatImage disp0, CFloatImage disp0y, CFloatImage disp1, int dir, float thresh, CByteImage &mask) { CShape sh = disp0.Shape(); int width = sh.width, height = sh.height; if (sh != disp1.Shape()) throw CError("shapes differ"); int ydisps = (sh == disp0y.Shape()); mask.ReAllocate(sh); mask.ClearPixels(); int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { float dx = disp0.Pixel(x, y, 0); float dy = (ydisps ? disp0y.Pixel(x, y, 0) : 0.0); if (dx == INFINITY) // unknown continue; mask.Pixel(x, y, 0) = 128; // occluded // find nonocc int x1 = (int)round(x + dir * dx); int y1 = (int)round(y + dy); if (x1 < 0 || x1 >= width || y1 < 0 || y1 >= height) continue; float dx1 = disp1.Pixel(x1, y1, 0); float diff = dx - dx1; if (fabs(diff) > thresh) continue; // fails cross checking -- occluded mask.Pixel(x, y, 0) = 255; // cross-checking OK } } }
// TO DO--------------------------------------------------------------------- // Loop through the harrisImage to threshold and compute the local maxima in a neighborhood // srcImage: image with Harris values // destImage: Assign 1 to a pixel if it is above a threshold and is the local maximum in 3x3 window, 0 otherwise. // You'll need to find a good threshold to use. void computeLocalMaxima(CFloatImage &srcImage,CByteImage &destImage) { int width = srcImage.Shape().width; int height = srcImage.Shape().height; double mean, stdDev; double sum = 0; double squareSum = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float pixel = srcImage.Pixel(x, y, 0); if (!(pixel >= 0 || pixel < 0)) { auto error = "TRUE"; } sum += srcImage.Pixel(x, y, 0); } } mean = sum / (float)(width * height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { squareSum += pow((srcImage.Pixel(x, y, 0) - mean), 2.); } } stdDev = sqrt(squareSum / (float)(width * height - 1)); int count = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { unsigned char *pixel = &destImage.Pixel(x, y, 0); if (srcImage.Pixel(x, y, 0) >= 3.*stdDev + mean && isLocalMax(srcImage, x, y)) { count++; *pixel = 1; } else { *pixel = 0; } } } }
void WTA(MRF::CostVal *dsi, int width, int height, int nD, CByteImage &disp) { CShape sh(width, height, 1); disp.ReAllocate(sh); int n = 0; for (int y = 0; y < height; y++) { uchar *row = &disp.Pixel(0, y, 0); for (int x = 0; x < width; x++) { int minval = dsi[n++]; // dsi(x,y,0) int mind = 0; for (int d = 1; d < nD; d++) { int val = dsi[n++]; // dsi(x,y,d) if (val < minval) { minval = val; mind = d; } } row[x] = mind; } } }
// Convert CFloatImage to CByteImage. void convertToByteImage(CFloatImage &floatImage, CByteImage &byteImage) { CShape sh = floatImage.Shape(); assert(floatImage.Shape().nBands == byteImage.Shape().nBands); for (int y=0; y<sh.height; y++) { for (int x=0; x<sh.width; x++) { for (int c=0; c<sh.nBands; c++) { float value = floor(255*floatImage.Pixel(x,y,c) + 0.5f); if (value < byteImage.MinVal()) { value = byteImage.MinVal(); } else if (value > byteImage.MaxVal()) { value = byteImage.MaxVal(); } // We have to flip the image and reverse the color // channels to get it to come out right. How silly! byteImage.Pixel(x,sh.height-y-1,sh.nBands-c-1) = (uchar) value; } } } }
bool LoadImageFile(const char *filename, CByteImage &image) { // Load the query image. printf("%s\n", filename); Fl_Shared_Image *fl_image = Fl_Shared_Image::get(filename); if (fl_image == NULL) { printf("TGA\n"); ReadFile(image, filename); return true; } else { printf("Not TGA\n"); CShape sh(fl_image->w(), fl_image->h(), 4); image = CByteImage(sh); // Convert the image to the CImage format. if (!convertImage(fl_image, image)) { printf("couldn't convert image to RGB format\n"); return false; } /* Set the alpha channel to 1 everywhere */ int w = sh.width; int h = sh.height; sh = image.Shape(); // printf("shape: %d, %d, %d\n", sh.width, sh.height, sh.nBands); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { image.Pixel(x, y, 3) = 255; } } return true; } }
void WriteFilePNG(CByteImage img, const char* filename) { img = removeRedundantBands(img); CShape sh = img.Shape(); int width = sh.width, height = sh.height, nBands = sh.nBands; // Make sure the image has the smallest number of bands before writing. // That is, if it's 4 bands with full alpha, reduce to 3 bands. // If it's 3 bands with constant colors, make it 1-band. FILE *stream = fopen(filename, "wb"); if (stream == 0) throw CError("WriteFilePNG: could not open %s", filename); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)pngfile_error, (png_error_ptr)NULL); if (!png_ptr) { fclose(stream); throw CError("WriteFilePNG: error creating png structure"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose(stream); throw CError("WriteFilePNG: error creating png structure"); } png_init_io(png_ptr, stream); int bits = 8; int colortype = nBands == 1 ? PNG_COLOR_TYPE_GRAY : nBands == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; png_set_IHDR(png_ptr, info_ptr, width, height, bits, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // write the file header information png_write_info(png_ptr, info_ptr); // swap the BGR pixels in the DiData structure to RGB png_set_bgr(png_ptr); // allocate a vector of row pointers std::vector<uchar *> rowPtrs; rowPtrs.resize(height); for (int y = 0; y<height; y++) rowPtrs[y] = &img.Pixel(0, y, 0); // write the whole image png_write_image(png_ptr, &rowPtrs[0]); // write the additional chunks to the PNG file (not really needed) png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); fclose (stream); }
/******************* TO DO 4 ********************* * AccumulateBlend: * INPUT: * img: a new image to be added to acc * acc: portion of the accumulated image where img is to be added * M: translation matrix for calculating a bounding box * blendWidth: width of the blending function (horizontal hat function; * try other blending functions for extra credit) * OUTPUT: * add a weighted copy of img to the subimage specified in acc * the first 3 band of acc records the weighted sum of pixel colors * the fourth band of acc records the sum of weight */ static void AccumulateBlend(CByteImage& img, CFloatImage& acc, CTransform3x3 M, float blendWidth) { /* Compute the bounding box of the image of the image */ int bb_min_x, bb_min_y, bb_max_x, bb_max_y; ImageBoundingBox(img, M, bb_min_x, bb_min_y, bb_max_x, bb_max_y); int imgWidth = img.Shape().width; int imgHeight = img.Shape().height; CTransform3x3 Minv = M.Inverse(); for (int y = bb_min_y; y <= bb_max_y; y++) { for (int x = bb_min_x; x < bb_max_x; x++) { /* Check bounds in destination */ if (x < 0 || x >= acc.Shape().width || y < 0 || y >= acc.Shape().height) continue; /* Compute source pixel and check bounds in source */ CVector3 p_dest, p_src; p_dest[0] = x; p_dest[1] = y; p_dest[2] = 1.0; p_src = Minv * p_dest; float x_src = (float) (p_src[0] / p_src[2]); float y_src = (float) (p_src[1] / p_src[2]); if (x_src < 0.0 || x_src >= img.Shape().width - 1 || y_src < 0.0 || y_src >= img.Shape().height - 1) continue; int xf = (int) floor(x_src); int yf = (int) floor(y_src); int xc = xf + 1; int yc = yf + 1; /* Skip black pixels */ if (img.Pixel(xf, yf, 0) == 0x0 && img.Pixel(xf, yf, 1) == 0x0 && img.Pixel(xf, yf, 2) == 0x0) continue; if (img.Pixel(xc, yf, 0) == 0x0 && img.Pixel(xc, yf, 1) == 0x0 && img.Pixel(xc, yf, 2) == 0x0) continue; if (img.Pixel(xf, yc, 0) == 0x0 && img.Pixel(xf, yc, 1) == 0x0 && img.Pixel(xf, yc, 2) == 0x0) continue; if (img.Pixel(xc, yc, 0) == 0x0 && img.Pixel(xc, yc, 1) == 0x0 && img.Pixel(xc, yc, 2) == 0x0) continue; double weight = 1.0; // *** BEGIN TODO *** // set weight properly //(see mosaics lecture slide on "feathering") P455 on notebook //Q:How to find the invalid distance ? -> double distance = ((imgWidth - x - 1)*(imgWidth - x - 1) + (imgHeight - y - 1)*(imgHeight - y - 1)); if (distance < blendWidth) { weight = distance / blendWidth; } // *** END TODO *** acc.Pixel(x, y, 0) += (float) (weight * img.PixelLerp(x_src, y_src, 0)); acc.Pixel(x, y, 1) += (float) (weight * img.PixelLerp(x_src, y_src, 1)); acc.Pixel(x, y, 2) += (float) (weight * img.PixelLerp(x_src, y_src, 2)); acc.Pixel(x, y, 3) += (float) weight; } } }
void evaldisp(CFloatImage disp, CFloatImage gtdisp, CByteImage mask, float badthresh, int maxdisp, int rounddisp) { CShape sh = gtdisp.Shape(); CShape sh2 = disp.Shape(); CShape msh = mask.Shape(); int width = sh.width, height = sh.height; int width2 = sh2.width, height2 = sh2.height; int scale = width / width2; if ((!(scale == 1 || scale == 2 || scale == 4)) || (scale * width2 != width) || (scale * height2 != height)) { printf(" disp size = %4d x %4d\n", width2, height2); printf("GT disp size = %4d x %4d\n", width, height); throw CError("GT disp size must be exactly 1, 2, or 4 * disp size"); } int usemask = (msh.width > 0 && msh.height > 0); if (usemask && (msh != sh)) throw CError("mask image must have same size as GT\n"); int n = 0; int bad = 0; int invalid = 0; float serr = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float gt = gtdisp.Pixel(x, y, 0); if (gt == INFINITY) // unknown continue; float d = scale * disp.Pixel(x / scale, y / scale, 0); float maxd = scale * maxdisp; // max disp range int valid = (d != INFINITY && d <= maxd * 1000); if (valid) { d = __max(0, __min(maxd, d)); // clip disps to max disp range } if (valid && rounddisp) d = round(d); float err = fabs(d - gt); if (usemask && mask.Pixel(x, y, 0) != 255) { // don't evaluate pixel } else { n++; if (valid) { serr += err; if (err > badthresh) { bad++; } } else {// invalid (i.e. hole in sparse disp map) invalid++; } } } } float badpercent = 100.0*bad/n; float invalidpercent = 100.0*invalid/n; float totalbadpercent = 100.0*(bad+invalid)/n; float avgErr = serr / (n - invalid); // CHANGED 10/14/2014 -- was: serr / n //printf("mask bad%.1f invalid totbad avgErr\n", badthresh); printf("%4.1f %6.2f %6.2f %6.2f %6.2f\n", 100.0*n/(width * height), badpercent, invalidpercent, totalbadpercent, avgErr); }
void ReadFilePNG(CByteImage& img, const char* filename) { // open the PNG input file FILE *stream = fopen(filename, "rb"); if (stream == 0) throw CError("ReadFilePNG: could not open %s", filename); // first check the eight byte PNG signature png_byte pbSig[8]; fread(pbSig, 1, 8, stream); if (!png_check_sig(pbSig, 8)) { fclose(stream); throw CError("ReadFilePNG: invalid PNG signature"); } // create the two png(-info) structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)pngfile_error, (png_error_ptr)NULL); if (!png_ptr) { fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } png_init_io(png_ptr, stream); png_set_sig_bytes(png_ptr, 8); // read all PNG info up to image data png_read_info(png_ptr, info_ptr); // get width, height, bit-depth and color-type int width, height, bits, colorType, nBands; png_uint_32 pwidth, pheight; png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, //(png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); width = pwidth; height = pheight; nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " w=%d, h=%d, %2d bits, %s, nB=%d", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); // get rid of lower-order byte in 16-bit images // TODO: could allow this and read in IntImage in this case... if (bits == 16) png_set_strip_16(png_ptr); // change palette color into RGB if (colorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); // want at least 8 bits if (bits < 8) png_set_expand(png_ptr); // if there is a transparent palette entry, create alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); // make gray images with alpha channel into RGBA -- TODO: or just ignore alpha? if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA) // colorType == PNG_COLOR_TYPE_GRAY // but leave gray images alone png_set_gray_to_rgb(png_ptr); // set the background color to draw transparent and alpha images over. // only needed for gray images with alpha if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA || colorType == PNG_COLOR_TYPE_GRAY) { png_color_16 *pBackground; if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } // if required set gamma conversion // this seems to cause problems, so let's just leave gamma alone. //double gamma; //if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { // //fprintf(stderr, "\n reading gamma %lf\n", gamma); //png_set_gamma(png_ptr, 1.0, gamma); //} // we need colors in BGR order, not RGB png_set_bgr(png_ptr); // always convert 3-band to 4-band images (add alpha): if (colorType == PNG_COLOR_TYPE_RGB) png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); // after the transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // get again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, //(png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); width = pwidth; height = pheight; nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " -> w=%d, h=%d, %2d bits, %s, nB=%d\n", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); if (! (nBands==1 || nBands==3 || nBands==4)) { fclose(stream); throw CError("ReadFilePNG: Can't handle nBands=%d", nBands); } // Set the image shape CShape sh(width, height, nBands); // Allocate the image if necessary img.ReAllocate(sh); // allocate a vector of row pointers std::vector<uchar *> rowPtrs; rowPtrs.resize(height); for (int y = 0; y<height; y++) rowPtrs[y] = &img.Pixel(0, y, 0); // read the whole image png_read_image(png_ptr, &rowPtrs[0]); // read the additional chunks in the PNG file (not really needed) png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(stream); }
/******************* TO DO ********************* * AccumulateBlend: * INPUT: * img: a new image to be added to acc * acc: portion of the accumulated image where img is to be added * M: the transformation mapping the input image 'img' into the output panorama 'acc' * blendWidth: width of the blending function (horizontal hat function; * try other blending functions for extra credit) * OUTPUT: * add a weighted copy of img to the subimage specified in acc * the first 3 band of acc records the weighted sum of pixel colors * the fourth band of acc records the sum of weight */ static void AccumulateBlend(CByteImage& img, CFloatImage& acc, CTransform3x3 M, float blendWidth) { // BEGIN TODO // Fill in this routine // get shape of acc and img CShape sh = img.Shape(); int width = sh.width; int height = sh.height; CShape shacc = acc.Shape(); int widthacc = shacc.width; int heightacc = shacc.height; // get the bounding box of img in acc int min_x, min_y, max_x, max_y; ImageBoundingBox(img, M, min_x, min_y, max_x, max_y); CVector3 p; double newx, newy; // Exposure Compensation double lumaScale = 1.0; double lumaAcc = 0.0; double lumaImg = 0.0; int cnt = 0; for (int ii = min_x; ii < max_x; ii++) for (int jj = min_y; jj < max_y; jj++) { // flag: current pixel black or not bool flag = false; p[0] = ii; p[1] = jj; p[2] = 1; p = M.Inverse() * p; newx = p[0] / p[2]; newy = p[1] / p[2]; // If in the overlapping region if (newx >=0 && newx < width && newy >=0 && newy < height) { if (acc.Pixel(ii,jj,0) == 0 && acc.Pixel(ii,jj,1) == 0 && acc.Pixel(ii,jj,2) == 0) flag = true; if (img.PixelLerp(newx,newy,0) == 0 && img.PixelLerp(newx,newy,1) == 0 && img.PixelLerp(newx,newy,2) == 0) flag = true; if (!flag) { // Compute Y using RGB (RGB -> YUV) lumaAcc = 0.299 * acc.Pixel(ii,jj,0) + 0.587 * acc.Pixel(ii,jj,1) + 0.114 * acc.Pixel(ii,jj,2); lumaImg = 0.299 * img.PixelLerp(newx,newy,0) + 0.587 * img.PixelLerp(newx,newy,1) + 0.114 * img.PixelLerp(newx,newy,2); if (lumaImg != 0) { double scale = lumaAcc / lumaImg; if (scale > 0.5 && scale < 2) { lumaScale += lumaAcc / lumaImg; cnt++; } } } } } if (cnt != 0) lumaScale = lumaScale / (double)cnt; else lumaScale = 1.0; // add every pixel in img to acc, feather the region withing blendwidth to the bounding box, // pure black pixels (caused by warping) are not added double weight; for (int ii = min_x; ii < max_x; ii++) for (int jj = min_y; jj < max_y; jj++) { p[0] = ii; p[1] = jj; p[2] = 1; p = M.Inverse() * p; newx = p[0] / p[2]; newy = p[1] / p[2]; if ((newx >= 0) && (newx < width-1) && (newy >= 0) && (newy < height-1)) { weight = 1.0; if ( (ii >= min_x) && (ii < (min_x+blendWidth)) ) weight = (ii-min_x) / blendWidth; if ( (ii <= max_x) && (ii > (max_x-blendWidth)) ) weight = (max_x-ii) / blendWidth; if (img.Pixel(iround(newx),iround(newy),0) == 0 && img.Pixel(iround(newx),iround(newy),1) == 0 && img.Pixel(iround(newx),iround(newy),2) == 0) weight = 0.0; double LerpR = img.PixelLerp(newx, newy, 0); double LerpG = img.PixelLerp(newx, newy, 1); double LerpB = img.PixelLerp(newx, newy, 2); double r = LerpR*lumaScale > 255.0 ? 255.0 : LerpR*lumaScale; double g = LerpG*lumaScale > 255.0 ? 255.0 : LerpG*lumaScale; double b = LerpB*lumaScale > 255.0 ? 255.0 : LerpB*lumaScale; acc.Pixel(ii,jj,0) += r * weight; acc.Pixel(ii,jj,1) += g * weight; acc.Pixel(ii,jj,2) += b * weight; acc.Pixel(ii,jj,3) += weight; } } printf("AccumulateBlend\n"); // END TODO }
void computeDSI(CByteImage im1, // source (reference) image CByteImage im2, // destination (match) image MRF::CostVal *&dsi, // computed cost volume int nD, // number of disparities int birchfield, // use Birchfield/Tomasi costs int squaredDiffs, // use squared differences int truncDiffs) // truncated differences { CShape sh = im1.Shape(); int width = sh.width, height = sh.height, nB = sh.nBands; dsi = new MRF::CostVal[width * height * nD]; int nColors = __min(3, nB); // worst value for sumdiff below int worst_match = nColors * (squaredDiffs ? 255 * 255 : 255); // truncation threshold - NOTE: if squared, don't multiply by nColors (Eucl. dist.) int maxsumdiff = squaredDiffs ? truncDiffs * truncDiffs : nColors * abs(truncDiffs); // value for out-of-bounds matches int badcost = __min(worst_match, maxsumdiff); int dsiIndex = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uchar *pix1 = &im1.Pixel(x, y, 0); for (int d = 0; d < nD; d++) { int x2 = x-d; int dsiValue; if (x2 >= 0 && d < nD) { // in bounds uchar *pix2 = &im2.Pixel(x2, y, 0); int sumdiff = 0; for (int b = 0; b < nColors; b++) { int diff = 0; if (birchfield) { // Birchfield/Tomasi cost int im1c = pix1[b]; int im1l = x == 0? im1c : (im1c + pix1[b - nB]) / 2; int im1r = x == width-1? im1c : (im1c + pix1[b + nB]) / 2; int im2c = pix2[b]; int im2l = x2 == 0? im2c : (im2c + pix2[b - nB]) / 2; int im2r = x2 == width-1? im2c : (im2c + pix2[b + nB]) / 2; int min1 = __min(im1c, __min(im1l, im1r)); int max1 = __max(im1c, __max(im1l, im1r)); int min2 = __min(im2c, __min(im2l, im2r)); int max2 = __max(im2c, __max(im2l, im2r)); int di1 = __max(0, __max(im1c - max2, min2 - im1c)); int di2 = __max(0, __max(im2c - max1, min1 - im2c)); diff = __min(di1, di2); } else { // simple absolute difference int di = pix1[b] - pix2[b]; diff = abs(di); } // square diffs if requested (Birchfield too...) sumdiff += (squaredDiffs ? diff * diff : diff); } // truncate diffs dsiValue = __min(sumdiff, maxsumdiff); } else { // out of bounds: use maximum truncated cost dsiValue = badcost; } //int x0=-140, y0=-150; //if (x==x0 && y==y0) // printf("dsi(%d,%d,%2d)=%3d\n", x, y, d, dsiValue); // The cost of pixel p and label l is stored at dsi[p*nLabels+l] dsi[dsiIndex++] = dsiValue; } } } //exit(1); }
// TODO: the following function should go somewhere else, perhaps in ImageIO.cpp // Make sure the image has the smallest number of bands before writing. // That is, if it's 4 bands with full alpha, reduce to 3 bands. // If it's 3 bands with constant colors, make it 1-band. CByteImage removeRedundantBands(CByteImage img) { CShape sh = img.Shape(); int w = sh.width, h = sh.height, nB = sh.nBands; int x, y; if (nB < 3) return img; // check if full alpha if alpha channel present bool fullAlpha = true; if (nB == 4) { for (y = 0; y < h && fullAlpha; y++) { uchar *pix = &img.Pixel(0, y, 0); for (x = 0; x < w; x++) { if (pix[3] != 255) { fullAlpha = false; break; } pix += nB; } } } if (!fullAlpha) return img; // check for equal colors bool equalColors = true; for (y = 0; y < h && equalColors; y++) { uchar *pix = &img.Pixel(0, y, 0); for (x = 0; x < w; x++) { if (pix[0] != pix[1] || pix[0] != pix[2] || pix[1] != pix[2]) { equalColors = false; break; } pix += nB; } } // at this point, if nB == 4 we can reduce to at least 3 bands, // and if equalColors we can reduce to 1 band. if (! equalColors && nB < 4) return img; int newNB = equalColors ? 1 : 3; if (DEBUG_ImageIOpng) fprintf(stderr, "reducing from %d to %d bands\n", nB, newNB); CShape sh2(w, h, newNB); CByteImage img2(sh2); for (y = 0; y < h; y++) { uchar *pix = &img.Pixel(0, y, 0); uchar *pix2 = &img2.Pixel(0, y, 0); for (x = 0; x < w; x++) { for (int b = 0; b < newNB; b++) { pix2[b] = pix[b]; } pix += nB; pix2 += newNB; } } return img2; }