//TO DO--------------------------------------------------------------------- //Loop through the image to compute the harris corner values as described in class // srcImage: grayscale of original image // harrisImage: populate the harris values per pixel in this image void computeHarrisValues(CFloatImage &srcImage, CFloatImage &harrisImage) { int h = srcImage.Shape().height; int w = srcImage.Shape().width; CFloatImage A(srcImage.Shape()); CFloatImage B(srcImage.Shape()); CFloatImage C(srcImage.Shape()); GetHarrisComponents(srcImage, A, B, C); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { double determinant = A.Pixel(x, y, 0) * C.Pixel(x, y, 0) - B.Pixel(x, y, 0)* B.Pixel(x, y, 0); double trace = A.Pixel(x, y, 0) + C.Pixel(x, y, 0); float *pixel = &harrisImage.Pixel(x, y, 0); if (trace == 0) { *pixel = 0; } else { *pixel = determinant / trace; } } } }
// Convert CFloatImage to CByteImage. void convertToByteImage(CFloatImage &floatImage, CByteImage &byteImage) { CShape sh = floatImage.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<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; } } } }
void rotation() { CFloatImage matrixImage = GetImageFromMatrix((float *)featureMatrix, 10, 10); CTransform3x3 translationNegative; CTransform3x3 translationPositive; CTransform3x3 rotation; CFloatImage postHomography; Feature f; f.x = 6; f.y = 5; f.angleRadians = PI; translationNegative = translationNegative.Translation(f.x,f.y); translationPositive = translationPositive.Translation(-f.x,-f.y); rotation = rotation.Rotation(-f.angleRadians * 180/ PI); WarpGlobal(matrixImage, postHomography, translationNegative*rotation*translationPositive, eWarpInterpLinear, eWarpInterpNearest); for (int i = 0; i < postHomography.Shape().height; i++) { for (int j = 0; j < postHomography.Shape().width; j++) { printf("%.0f\t", postHomography.Pixel(j, i, 0)); } printf("\n"); } }
static void ConvolveRow2D(CFloatImage& buffer, CFloatImage& kernel, float dst[], int n) { CShape kShape = kernel.Shape(); int kX = kShape.width; int kY = kShape.height; CShape bShape = buffer.Shape(); int nB = bShape.nBands; for (int i = 0; i < n; i++) { for (int b = 0; b < nB; b++) { float sum = 0.0f; for (int k = 0; k < kY; k++) { float* kPtr = &kernel.Pixel(0, k, 0); float* bPtr = &buffer.Pixel(i, k, b); for (int l = 0; l < kX; l++, bPtr += nB) sum += kPtr[l] * bPtr[0]; } *dst++ = sum; } } }
/******************* 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 *** }
void ComputeHarrisFeatures(CFloatImage &image, FeatureSet &features) { //Create grayscale image used for Harris detection CFloatImage grayImage=ConvertToGray(image); //Create image to store Harris values CFloatImage harrisImage(image.Shape().width,image.Shape().height,1); //Create image to store local maximum harris values as 1, other pixels 0 CByteImage harrisMaxImage(image.Shape().width,image.Shape().height,1); //compute Harris values puts harris values at each pixel position in harrisImage. //You'll need to implement this function. computeHarrisValues(grayImage, harrisImage); // Threshold the harris image and compute local maxima. You'll need to implement this function. computeLocalMaxima(harrisImage,harrisMaxImage); // Prints out the harris image for debugging purposes CByteImage tmp(harrisImage.Shape()); convertToByteImage(harrisImage, tmp); WriteFile(tmp, "harris.tga"); // TO DO-------------------------------------------------------------------- //Loop through feature points in harrisMaxImage and fill in information needed for //descriptor computation for each point above a threshold. We fill in id, type, //x, y, and angle. CFloatImage A(grayImage.Shape()); CFloatImage B(grayImage.Shape()); CFloatImage C(grayImage.Shape()); CFloatImage partialX(grayImage.Shape()); CFloatImage partialY(grayImage.Shape()); GetHarrisComponents(grayImage, A, B, C, &partialX, &partialY); int featureCount = 0; for (int y=0;y<harrisMaxImage.Shape().height;y++) { for (int x=0;x<harrisMaxImage.Shape().width;x++) { // Skip over non-maxima if (harrisMaxImage.Pixel(x, y, 0) == 0) continue; //TO DO--------------------------------------------------------------------- // Fill in feature with descriptor data here. Feature f; f.type = 2; f.id = featureCount++; f.x = x; f.y = y; f.angleRadians = GetCanonicalOrientation(x, y, A, B, C, partialX, partialY); //atan(partialY.Pixel(x, y, 0)/partialX.Pixel(x, y, 0)); // Add the feature to the list of features features.push_back(f); } } }
/******************* 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 }
// 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; } } }
void Convolve(CImageOf<T> src, CImageOf<T>& dst, CFloatImage kernel) { // Determine the shape of the kernel and source image CShape kShape = kernel.Shape(); CShape sShape = src.Shape(); // Allocate the result, if necessary dst.ReAllocate(sShape, false); if (sShape.width * sShape.height * sShape.nBands == 0) return; // Do the convolution for (int y = 0; y < sShape.height; y++) for (int x = 0; x < sShape.width; x++) for (int c = 0; c < sShape.nBands; c++) { double sum = 0; for (int kx = 0; kx < kShape.width; kx++) for (int ky = 0; ky < kShape.height; ky++) if ((x-kernel.origin[0]+kx >= 0) && (x-kernel.origin[0]+kx < sShape.width) && (y-kernel.origin[1]+ky >= 0) && (y-kernel.origin[1]+ky < sShape.height)) sum += kernel.Pixel(kx,ky,0) * src.Pixel(x-kernel.origin[0]+kx,y-kernel.origin[1]+ky,c); dst.Pixel(x,y,c) = (T) __max(dst.MinVal(), __min(dst.MaxVal(), sum)); } }
// Compute silly example features. This doesn't do anything // meaningful, but may be useful to use as an example. void dummyComputeFeatures(CFloatImage &image, FeatureSet &features) { CShape sh = image.Shape(); Feature f; for (int y=0; y<sh.height; y++) { for (int x=0; x<sh.width; x++) { double r = image.Pixel(x,y,0); double g = image.Pixel(x,y,1); double b = image.Pixel(x,y,2); if ((int)(255*(r+g+b)+0.5) % 100 == 1) { // If the pixel satisfies this meaningless criterion, // make it a feature. f.type = 1; f.id += 1; f.x = x; f.y = y; f.data.resize(1); f.data[0] = r + g + b; features.push_back(f); } } } }
void ConvolveRow(CImageOf<T> buffer, CFloatImage kernel, T* dst, int n, T minVal, T maxVal) { CShape kShape = kernel.Shape(); int kX = kShape.width; int kY = kShape.height; CShape bShape = buffer.Shape(); int nB = bShape.nBands; for (int i = 0; i < n; i++) { for (int b = 0; b < nB; b++) { float sum = 0.0f; for (int k = 0; k < kY; k++) { float* kPtr = &kernel.Pixel(0, k, 0); T* bPtr = &buffer.Pixel(i, k, b); for (int l = 0; l < kX; l++, bPtr += nB) sum += kPtr[l] * bPtr[0]; } *dst++ = (T) __max(minVal, __min(maxVal, sum)); } } }
void ConvolveSeparable(CImageOf<T> src, CImageOf<T>& dst, CFloatImage x_kernel, CFloatImage y_kernel, float scale, float offset, int decimate, int interpolate) { // Allocate the result, if necessary CShape dShape = src.Shape(); if (decimate > 1) { dShape.width = (dShape.width + decimate-1) / decimate; dShape.height = (dShape.height + decimate-1) / decimate; } dst.ReAllocate(dShape, false); // Allocate the intermediate images CImageOf<T> tmpImg1(src.Shape()); CImageOf<T> tmpImg2(src.Shape()); // Create a proper vertical convolution kernel CFloatImage v_kernel(1, y_kernel.Shape().width, 1); for (int k = 0; k < y_kernel.Shape().width; k++) v_kernel.Pixel(0, k, 0) = y_kernel.Pixel(k, 0, 0); v_kernel.origin[1] = y_kernel.origin[0]; // Perform the two convolutions Convolve(src, tmpImg1, x_kernel, 1.0f, 0.0f); Convolve(tmpImg1, tmpImg2, v_kernel, scale, offset); // Downsample or copy for (int y = 0; y < dShape.height; y++) { T* sPtr = &tmpImg2.Pixel(0, y * decimate, 0); T* dPtr = &dst.Pixel(0, y, 0); int nB = dShape.nBands; for (int x = 0; x < dShape.width; x++) { for (int b = 0; b < nB; b++) dPtr[b] = sPtr[b]; sPtr += decimate * nB; dPtr += nB; } } interpolate++; // to get rid of "unused parameter" warning }
// 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 GetHarrisComponents(CFloatImage &srcImage, CFloatImage &A, CFloatImage &B, CFloatImage &C, CFloatImage *partialX, CFloatImage *partialY) { int w = srcImage.Shape().width; int h = srcImage.Shape().height; CFloatImage *partialXPtr; CFloatImage *partialYPtr; if (partialX != nullptr && partialY != nullptr) { partialXPtr = partialX; partialYPtr = partialY; } else { partialXPtr = new CFloatImage(srcImage.Shape()); partialYPtr = new CFloatImage(srcImage.Shape()); } CFloatImage partialXX(srcImage.Shape()); CFloatImage partialYY(srcImage.Shape()); CFloatImage partialXY(srcImage.Shape()); CFloatImage gaussianImage = GetImageFromMatrix((float *)gaussian5x5Float, 5, 5); Convolve(srcImage, *partialXPtr, ConvolveKernel_SobelX); Convolve(srcImage, *partialYPtr, ConvolveKernel_SobelY); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { float *xxPixel = &partialXX.Pixel(x, y, 0); float *yyPixel = &partialYY.Pixel(x, y, 0); float *xyPixel = &partialXY.Pixel(x, y, 0); // The 1/8 factor is to do the scaling inherent in sobel filtering *xxPixel = pow((double)(1./8. *8. * partialXPtr->Pixel(x, y, 0)), 2.); *yyPixel = pow((double)(1./8. *8. * partialYPtr->Pixel(x, y, 0)), 2.); *xyPixel = pow(1./8. *8., 2.) * partialXPtr->Pixel(x, y, 0) * partialYPtr->Pixel(x, y, 0); } } Convolve(partialXX, A, gaussianImage); Convolve(partialXY, B, gaussianImage); Convolve(partialYY, C, gaussianImage); }
//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; } } } }
void ConvolveSeparable(CImageOf<T> src, CImageOf<T>& dst, CFloatImage x_kernel, CFloatImage y_kernel, int subsample) { // Allocate the result, if necessary CShape dShape = src.Shape(); if (subsample > 1) { dShape.width = (dShape.width + subsample-1) / subsample; dShape.height = (dShape.height + subsample-1) / subsample; } dst.ReAllocate(dShape, false); // Allocate the intermediate images CImageOf<T> tmpImg1(src.Shape()); CImageOf<T> tmpImg2(src.Shape()); // Create a proper vertical convolution kernel CFloatImage v_kernel(1, y_kernel.Shape().width, 1); for (int k = 0; k < y_kernel.Shape().width; k++) v_kernel.Pixel(0, k, 0) = y_kernel.Pixel(k, 0, 0); v_kernel.origin[1] = y_kernel.origin[0]; // Perform the two convolutions Convolve(src, tmpImg1, x_kernel); Convolve(tmpImg1, tmpImg2, v_kernel); // Downsample or copy for (int y = 0; y < dShape.height; y++) { T* sPtr = &tmpImg2.Pixel(0, y * subsample, 0); T* dPtr = &dst.Pixel(0, y, 0); int nB = dShape.nBands; for (int x = 0; x < dShape.width; x++) { for (int b = 0; b < nB; b++) dPtr[b] = sPtr[b]; sPtr += subsample * nB; dPtr += nB; } } }
CFloatImage GetXWindowAroundPixel(CFloatImage srcImage, int x, int y, int size) { float *matrix = new float[size * size]; for(int row=(y-(size-1)/2); row<=(y+(size-1)/2); row++) { for(int col=(x-(size-1)/2);col<=(x+(size-1)/2);col++) { if(row<0 || row>=srcImage.Shape().height || col<0 || col>=srcImage.Shape().width) { matrix[(row-(y-(size-1)/2))*size + (col-(x-(size-1)/2))] = 0.; } else { matrix[(row-(y-(size-1)/2))*size + (col-(x-(size-1)/2))] = srcImage.Pixel(col, row, 0); } } } return GetImageFromMatrix(matrix, size, size); }
void Convolve(CImageOf<T> src, CImageOf<T>& dst, CFloatImage kernel, float scale, float offset) { // Determine the shape of the kernel and row buffer CShape kShape = kernel.Shape(); CShape sShape = src.Shape(); CShape bShape(sShape.width + kShape.width, kShape.height, sShape.nBands); int bWidth = bShape.width * bShape.nBands; // Allocate the result, if necessary, and the row buffer dst.ReAllocate(sShape, false); CFloatImage buffer(bShape); if (sShape.width * sShape.height * sShape.nBands == 0) return; CFloatImage output(CShape(sShape.width, 1, sShape.nBands)); // Fill up the row buffer initially for (int k = 0; k < kShape.height; k++) FillRowBuffer(&buffer.Pixel(0, k, 0), src, kernel, k, bWidth); // Determine if clipping is required // (we assume up-conversion to float never requires clipping, i.e., // floats have the highest dynamic range) T minVal = dst.MinVal(); T maxVal = dst.MaxVal(); if (minVal <= buffer.MinVal() && maxVal >= buffer.MaxVal()) minVal = maxVal = 0; // Process each row for (int y = 0; y < sShape.height; y++) { // Do the convolution ConvolveRow2D(buffer, kernel, &output.Pixel(0, 0, 0), sShape.width); // Scale, offset, and type convert ScaleAndOffsetLine(&output.Pixel(0, 0, 0), &dst.Pixel(0, y, 0), sShape.width * sShape.nBands, scale, offset, minVal, maxVal); // Shift up the row buffer and fill the last line if (y < sShape.height-1) { int k; for (k = 0; k < kShape.height-1; k++) memcpy(&buffer.Pixel(0, k, 0), &buffer.Pixel(0, k+1, 0), bWidth * sizeof(float)); FillRowBuffer(&buffer.Pixel(0, k, 0), src, kernel, y+k+1, bWidth); } } }
void WarpLocal(CImageOf<T> src, CImageOf<T>& dst, CFloatImage uv, bool relativeCoords, EWarpInterpolationMode interp, float cubicA) { // Check that dst is of the right shape CShape sh(uv.Shape().width, uv.Shape().height, src.Shape().nBands); dst.ReAllocate(sh); // Allocate a row buffer for coordinates int n = sh.width; std::vector<float> rowBuf; rowBuf.resize(n*2); // Precompute the cubic interpolant if (interp == eWarpInterpCubic) InitializeCubicLUT(cubicA); // Process each row for (int y = 0; y < sh.height; y++) { float *uvP = &uv .Pixel(0, y, 0); float *xyP = (relativeCoords) ? &rowBuf[0] : uvP; T *dstP = &dst.Pixel(0, y, 0); // Convert to absolute coordinates if necessary if (relativeCoords) { for (int x = 0; x < n; x++) { xyP[2*x+0] = x + uvP[2*x+0]; xyP[2*x+1] = y + uvP[2*x+1]; } } // Resample the line WarpLine(src, dstP, xyP, n, sh.nBands, interp, src.MinVal(), src.MaxVal()); } }
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); } } } }
cv::Mat FlowIOOpenCVWrapper::read(std::string path) { CFloatImage flow; ReadFlowFile(flow, path.c_str()); int rows = flow.Shape().height; int cols = flow.Shape().width; assert(rows > 0); assert(cols > 0); assert(flow.Shape().nBands == 2); cv::Mat matFlow(rows, cols, CV_32FC2, cv::Scalar(0, 0)); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { matFlow.at<cv::Vec2f>(i, j)[0] = flow.Pixel(j, i, 0); matFlow.at<cv::Vec2f>(i, j)[1] = flow.Pixel(j, i, 1); } } return matFlow; }
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 } } }
bool isLocalMax(CFloatImage srcImage, int x, int y) { int width = srcImage.Shape().width; int height = srcImage.Shape().height; float centerPixel = srcImage.Pixel(x, y, 0); for (int row = 0; row < 5; row++) { for (int col = 0; col < 5; col++) { int xOffset = x - 2 + col; int yOffset = y - 2 + row; if (xOffset == x && yOffset == y) { continue; } float pixelAtOffset; if (xOffset < 0 || yOffset < 0 || xOffset >= width || yOffset >= height) { pixelAtOffset = 0.; } else { pixelAtOffset = srcImage.Pixel(xOffset, yOffset, 0); } if (pixelAtOffset >= centerPixel) { return false; } } } return true; }
// get min and max (non-INF) values void getMinMax(CFloatImage fimg, float& vmin, float& vmax) { CShape sh = fimg.Shape(); int width = sh.width, height = sh.height; vmin = INFINITY; vmax = -INFINITY; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float f = fimg.Pixel(x, y, 0); if (f == INFINITY) continue; vmin = min(f, vmin); vmax = max(f, vmax); } } }
// Compute features using Harris corner detection method void ComputeHarrisFeatures(CFloatImage &image, FeatureSet &features) { // Create grayscale image used for Harris detection CFloatImage grayImage = ConvertToGray(image); // Create image to store Harris values CFloatImage harrisImage(image.Shape().width,image.Shape().height,1); // Create image to store local maximum harris values as 1, other pixels 0 CByteImage harrisMaxImage(image.Shape().width,image.Shape().height,1); // Create image to store orientation values CFloatImage orientationImage(image.Shape().width, image.Shape().height, 1); // Compute the harris score at each pixel position, storing the result in in harrisImage. computeHarrisValues(grayImage, harrisImage, orientationImage); // Threshold the harris image and compute local maxima. computeLocalMaxima(harrisImage,harrisMaxImage); // Save images CByteImage tmp(harrisImage.Shape()); CByteImage tmp2(harrisImage.Shape()); convertToByteImage(harrisImage, tmp); convertToByteImage(grayImage, tmp2); WriteFile(tmp2, "grayImg.tga"); WriteFile(tmp, "harris.tga"); WriteFile(harrisMaxImage, "harrisMax.tga"); // Loop through feature points in harrisMaxImage and fill in id, type, x, y, and angle // information needed for descriptor computation for each feature point, then add them // to feature set int id = 0; for (int y=0; y < harrisMaxImage.Shape().height; y++) { for (int x=0; x < harrisMaxImage.Shape().width; x++) { if (harrisMaxImage.Pixel(x, y, 0) == 1) { Feature f; f.id = id; f.type = 2; f.x = x; f.y = y; f.angleRadians = orientationImage.Pixel(x,y,0); features.push_back(f); id++; } } } }
void subsample(Feature* f, int imgSize, CFloatImage gaussianImage) { vector<double, std::allocator<double>>::iterator it; CFloatImage img = featureToImage(*f, imgSize, imgSize); CFloatImage blurredImg(img.Shape()); Convolve(img, blurredImg, gaussianImage); featuresFromImage(f,blurredImg,imgSize,imgSize); int count = 0; for(int y=0; y<imgSize; y++) { for(int x=0; x<imgSize; x++) { if(x%2 == 0 || y%2 == 0) { f->data.erase(f->data.begin() + count); } else { count++; } } } }
void ConvolveSeparable(CImageOf<T> src, CImageOf<T>& dst, CFloatImage x_kernel, CFloatImage y_kernel, float scale, float offset, int decimate, int interpolate) { // Allocate the result, if necessary CShape dShape = src.Shape(); if (decimate > 1) { dShape.width = (dShape.width + decimate-1) / decimate; dShape.height = (dShape.height + decimate-1) / decimate; } dst.ReAllocate(dShape, false); // Allocate the intermediate images CImageOf<T> tmpImg1(src.Shape()); //CImageOf<T> tmpImgCUDA(src.Shape()); CImageOf<T> tmpImg2(src.Shape()); // Create a proper vertical convolution kernel CFloatImage v_kernel(1, y_kernel.Shape().width, 1); for (int k = 0; k < y_kernel.Shape().width; k++) v_kernel.Pixel(0, k, 0) = y_kernel.Pixel(k, 0, 0); v_kernel.origin[1] = y_kernel.origin[0]; #ifdef RUN_ON_GPU // Modifications for integrating CUDA kernels BinomialFilterType type; profilingTimer->startTimer(); // CUDA Convolve switch (x_kernel.Shape().width) { case 3: type = BINOMIAL6126; break; case 5: type = BINOMIAL14641; break; default: // Unsupported kernel case throw CError("Convolution kernel Unknown"); assert(false); } // Skip copy if decimation is not required if (decimate != 1) CudaConvolveXY(src, tmpImg2, type); else CudaConvolveXY(src, dst, type); printf("\nGPU convolution time = %f ms\n", profilingTimer->stopAndGetTimerValue()); #else profilingTimer->startTimer(); //VerifyComputedData(&tmpImg2.Pixel(0, 0, 0), &tmpImgCUDA.Pixel(0, 0, 0), 7003904); // Perform the two convolutions Convolve(src, tmpImg1, x_kernel, 1.0f, 0.0f); Convolve(tmpImg1, tmpImg2, v_kernel, scale, offset); printf("\nCPU Convolution time = %f ms\n", profilingTimer->stopAndGetTimerValue()); #endif profilingTimer->startTimer(); // Downsample or copy // Skip decimate and recopy if not required #ifdef RUN_ON_GPU if (decimate != 1) { #endif for (int y = 0; y < dShape.height; y++) { T* sPtr = &tmpImg2.Pixel(0, y * decimate, 0); T* dPtr = &dst.Pixel(0, y, 0); int nB = dShape.nBands; for (int x = 0; x < dShape.width; x++) { for (int b = 0; b < nB; b++) dPtr[b] = sPtr[b]; sPtr += decimate * nB; dPtr += nB; } } #ifdef RUN_ON_GPU } #endif printf("\nDecimate/Recopy took = %f ms\n", profilingTimer->stopAndGetTimerValue()); }
/******************* 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); }
/******************* 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 }