Feature TinyImageFeatureExtractor::operator()(const CByteImage& img_) const { CFloatImage tinyImg(_targetW, _targetH, 1); /******** BEGIN TODO ********/ // Compute tiny image feature, output should be _targetW by _targetH a grayscale image // Steps are: // 1) Convert image to grayscale (see convertRGB2GrayImage in Utils.h) // 2) Resize image to be _targetW by _targetH // // Useful functions: // convertRGB2GrayImage, TypeConvert, WarpGlobal CByteImage gray; CFloatImage grayF; convertRGB2GrayImage(img_, gray); TypeConvert(gray, grayF); CTransform3x3 scale = CTransform3x3::Scale(1.* img_.Shape().width / _targetW, 1.* img_.Shape().height/ _targetH); WarpGlobal(grayF, tinyImg, scale, eWarpInterpLinear); /******** END TODO ********/ return tinyImg; }
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"); } }
void WarpInstantiate(void) { CByteImage i1; CFloatImage uv1; WarpLocal(i1, i1, uv1, false, eWarpInterpLinear, 1.0f); CTransform3x3 M; WarpGlobal(i1, i1, M, eWarpInterpLinear, 1.0f); }
/******************* TO DO 5 ********************* * BlendImages: * INPUT: * ipv: list of input images and their relative positions in the mosaic * blendWidth: width of the blending function * OUTPUT: * create & return final mosaic by blending all images * and correcting for any vertical drift */ CByteImage BlendImages(CImagePositionV& ipv, float blendWidth) { // Assume all the images are of the same shape (for now) CByteImage& img0 = ipv[0].img; CShape sh = img0.Shape(); int width = sh.width; int height = sh.height; int nBands = sh.nBands; int dim[2] = {width, height}; // Compute the bounding box for the mosaic int n = ipv.size(); float min_x = 0, min_y = 0; float max_x = 0, max_y = 0; int i; float dy = 0; for (i = 0; i < n; i++) { CTransform3x3 &pos = ipv[i].position; CVector3 corners[4];//表示图片的4个角的坐标,分别为左下,右下,左上,右上 corners[0][0] = 0.0; corners[0][1] = 0.0; corners[0][2] = 1.0; corners[1][0] = width - 1; corners[1][1] = 0.0; corners[1][2] = 1.0; corners[2][0] = 0.0; corners[2][1] = height - 1; corners[2][2] = 1.0; corners[3][0] = width - 1; corners[3][1] = height - 1; corners[3][2] = 1.0; corners[0] = pos * corners[0]; corners[1] = pos * corners[1]; corners[2] = pos * corners[2]; corners[3] = pos * corners[3]; corners[0][0] /= corners[0][2]; corners[0][1] /= corners[0][2]; corners[1][0] /= corners[0][2]; corners[1][1] /= corners[0][2]; corners[2][0] /= corners[0][2]; corners[2][1] /= corners[0][2]; corners[3][0] /= corners[0][2]; corners[3][1] /= corners[0][2]; // *** BEGIN TODO #1 *** // add some code here to update min_x, ..., max_y //Use c0 and c3 to get the range of x and y. int iminx, iminy, imaxx, imaxy; ImageBoundingBox(img0, pos, iminx, iminy, imaxx, imaxy); if (i == 0) { dy += imaxy; } if (i == n - 1) { dy -= imaxy; } /*if (min_x > corners[0][0]) { min_x = corners[0][0]; } if (max_x < corners[3][0]) { max_x = corners[3][0]; } if (min_y > corners[0][1]) { min_y = corners[0][1]; } if (max_y < corners[3][1]) { max_y = corners[3][1]; } */ min_x = min(min_x, float(iminx)); min_y = min(min_y, float(iminy)); max_x = max(max_x, float(imaxx)); max_y = max(max_y, float(imaxy)); // *** END TODO #1 *** } // Create a floating point accumulation image CShape mShape((int)(ceil(max_x) - floor(min_x)), (int)(ceil(max_y) - floor(min_y)), nBands); CFloatImage accumulator(mShape); accumulator.ClearPixels(); double x_init, x_final; double y_init, y_final; // Add in all of the images for (i = 0; i < n; i++) { CTransform3x3 &M = ipv[i].position; CTransform3x3 M_t = CTransform3x3::Translation(-min_x, -min_y) * M; CByteImage& img = ipv[i].img; // Perform the accumulation AccumulateBlend(img, accumulator, M_t, blendWidth); if (i == 0) { CVector3 p; p[0] = 0.5 * width; p[1] = 0.0; p[2] = 1.0; p = M_t * p; x_init = p[0]; y_init = p[1]; } else if (i == n - 1) { CVector3 p; p[0] = 0.5 * width; p[1] = 0.0; p[2] = 1.0; p = M_t * p; x_final = p[0]; y_final = p[1]; } } // Normalize the results CByteImage compImage(mShape); NormalizeBlend(accumulator, compImage); bool debug_comp = false; if (debug_comp) WriteFile(compImage, "tmp_comp.tga"); // Allocate the final image shape CShape cShape(mShape.width - width, height, nBands); CByteImage croppedImage(cShape); // Compute the affine deformation CTransform3x3 A = CTransform3x3(); // *** BEGIN TODO #2 *** // fill in the right entries in A to trim the left edge and // to take out the vertical drift A[0][2] = width /2; A[1][0] = dy / (mShape.width - width); // *** END TODO #2 *** // Warp and crop the composite WarpGlobal(compImage, croppedImage, A, eWarpInterpLinear); // WarpGlobal(compImage, croppedImage, A, eWarpInterpNearest); //similar as linear // WarpGlobal(compImage, croppedImage, A, eWarpInterpCubic); //all pixels are black return croppedImage; }
// Compute MOPs descriptors. void ComputeMOPSDescriptors(CFloatImage &image, FeatureSet &features) { CFloatImage grayImage=ConvertToGray(image); CFloatImage blurredImage; Convolve(grayImage, blurredImage, ConvolveKernel_7x7); CFloatImage postHomography = CFloatImage(); CFloatImage gaussianImage = GetImageFromMatrix((float *)gaussian5x5Float, 5, 5); //first make the image invariant to changes in illumination by subtracting off the mean int grayHeight = grayImage.Shape().height; int grayWidth = grayImage.Shape().width; // now make this rotation invariant vector<Feature>::iterator featureIterator = features.begin(); while (featureIterator != features.end()) { Feature &f = *featureIterator; CTransform3x3 scaleTransform = CTransform3x3(); CTransform3x3 translationNegative; CTransform3x3 translationPositive; CTransform3x3 rotation; double scaleFactor = 41/8; scaleTransform[0][0] = scaleFactor; scaleTransform[1][1] = scaleFactor; translationNegative = translationNegative.Translation(f.x,f.y); translationPositive = translationPositive.Translation(-4, -4); rotation = rotation.Rotation(f.angleRadians * 180/ PI); CTransform3x3 finalTransformation = translationNegative * rotation * scaleTransform * translationPositive; //CFloatImage sample61x61Window = //CFloatImage pixelWindow = GetXWindowAroundPixel(grayImage, f.x, f.y, 61); WarpGlobal(blurredImage, postHomography, finalTransformation, eWarpInterpLinear, 1.0f); //now we get the 41x41 box around the feature for(int row=0; row< 8; row++) { for(int col=0;col< 8;col++) { f.data.push_back(postHomography.Pixel(col, row, 0)); } } /* // now we do the subsampling first round to reduce to a 20x20 int imgSize = 41; subsample(&f, imgSize, gaussianImage); //second round of subsampling to get it to a 10x10 imgSize = 20; subsample(&f, imgSize, gaussianImage); imgSize = 10; 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 == 3 || x == 7 || y == 3 || y == 7) { f.data.erase(f.data.begin() + count); } else { count++; } } } */ normalizeIntensities(&f, 8, 8); featureIterator++; } }
HOGFeatureExtractor::HOGFeatureExtractor(int nAngularBins, bool unsignedGradients, int cellSize): _nAngularBins(nAngularBins), _unsignedGradients(unsignedGradients), _cellSize(cellSize) { _kernelDx.ReAllocate(CShape(3, 1, 1), derivKvals, false, 1); _kernelDx.origin[0] = 1; _kernelDy.ReAllocate(CShape(1, 3, 1), derivKvals, false, 1); _kernelDy.origin[0] = 1; // For visualization // A set of patches representing the bin orientations. When drawing a hog cell // we multiply each patch by the hog bin value and add all contributions up to // form the visual representation of one cell. Full HOG is achieved by stacking // the viz for individual cells horizontally and vertically. _oriMarkers.resize(_nAngularBins); const int ms = 11; CShape markerShape(ms, ms, 1); // First patch is a horizontal line _oriMarkers[0].ReAllocate(markerShape, true); _oriMarkers[0].ClearPixels(); for(int i = 1; i < ms - 1; i++) _oriMarkers[0].Pixel(/*floor(*/ ms/2 /*)*/, i, 0) = 1; #if 0 // debug std::cout << "DEBUG:" << __FILE__ << ":" << __LINE__ << std::endl; for(int i = 0; i < ms; i++) { for(int j = 0; j < ms; j++) { std::cout << _oriMarkers[0].Pixel(j, i, 0) << " "; } std::cout << std::endl; } std::cout << std::endl; char debugFName[2000]; sprintf(debugFName, "/tmp/debug%03d.tga", 0); PRINT_EXPR(debugFName); WriteFile(_oriMarkers[0], debugFName); #endif // The other patches are obtained by rotating the first one CTransform3x3 T = CTransform3x3::Translation((ms - 1) / 2.0, (ms - 1) / 2.0); for(int angBin = 1; angBin < _nAngularBins; angBin++) { double theta; if(unsignedGradients) theta = 180.0 * (double(angBin) / _nAngularBins); else theta = 360.0 * (double(angBin) / _nAngularBins); CTransform3x3 R = T * CTransform3x3::Rotation(theta) * T.Inverse(); _oriMarkers[angBin].ReAllocate(markerShape, true); _oriMarkers[angBin].ClearPixels(); WarpGlobal(_oriMarkers[0], _oriMarkers[angBin], R, eWarpInterpLinear); #if 0 // debug char debugFName[2000]; sprintf(debugFName, "/tmp/debug%03d.tga", angBin); PRINT_EXPR(debugFName); WriteFile(_oriMarkers[angBin], debugFName); #endif } }
/******************* TO DO 5 ********************* * BlendImages: * INPUT: * ipv: list of input images and their relative positions in the mosaic * blendWidth: width of the blending function * OUTPUT: * create & return final mosaic by blending all images * and correcting for any vertical drift */ CByteImage BlendImages(CImagePositionV& ipv, float blendWidth) { // Assume all the images are of the same shape (for now) CByteImage& img0 = ipv[0].img; CShape sh = img0.Shape(); int width = sh.width; int height = sh.height; int nBands = sh.nBands; // int dim[2] = {width, height}; int n = ipv.size(); if (n == 0) return CByteImage(0,0,1); bool is360 = false; // Hack to detect if this is a 360 panorama if (ipv[0].imgName == ipv[n-1].imgName) is360 = true; // Compute the bounding box for the mosaic float min_x = FLT_MAX, min_y = FLT_MAX; float max_x = 0, max_y = 0; int i; for (i = 0; i < n; i++) { CTransform3x3 &T = ipv[i].position; // BEGIN TODO // add some code here to update min_x, ..., max_y printf("TODO: %s:%d\n", __FILE__, __LINE__); // END TODO } // Create a floating point accumulation image CShape mShape((int)(ceil(max_x) - floor(min_x)), (int)(ceil(max_y) - floor(min_y)), nBands + 1); CFloatImage accumulator(mShape); accumulator.ClearPixels(); double x_init, x_final; double y_init, y_final; // Add in all of the images for (i = 0; i < n; i++) { // Compute the sub-image involved CTransform3x3 &M = ipv[i].position; CTransform3x3 M_t = CTransform3x3::Translation(-min_x, -min_y) * M; CByteImage& img = ipv[i].img; // Perform the accumulation AccumulateBlend(img, accumulator, M_t, blendWidth); if (i == 0) { CVector3 p; p[0] = 0.5 * width; p[1] = 0.0; p[2] = 1.0; p = M_t * p; x_init = p[0]; y_init = p[1]; } else if (i == n - 1) { CVector3 p; p[0] = 0.5 * width; p[1] = 0.0; p[2] = 1.0; p = M_t * p; x_final = p[0]; y_final = p[1]; } } // Normalize the results mShape = CShape((int)(ceil(max_x) - floor(min_x)), (int)(ceil(max_y) - floor(min_y)), nBands); CByteImage compImage(mShape); NormalizeBlend(accumulator, compImage); bool debug_comp = false; if (debug_comp) WriteFile(compImage, "tmp_comp.tga"); // Allocate the final image shape int outputWidth = 0; if (is360) { outputWidth = mShape.width - width; } else { outputWidth = mShape.width; } CShape cShape(outputWidth, mShape.height, nBands); CByteImage croppedImage(cShape); // Compute the affine transformation CTransform3x3 A = CTransform3x3(); // identify transform to initialize // BEGIN TODO // fill in appropriate entries in A to trim the left edge and // to take out the vertical drift if this is a 360 panorama // (i.e. is360 is true) printf("TODO: %s:%d\n", __FILE__, __LINE__); // END TODO // Warp and crop the composite WarpGlobal(compImage, croppedImage, A, eWarpInterpLinear); return croppedImage; }
// Compute MOPs descriptors. void ComputeMOPSDescriptors(CFloatImage &image, FeatureSet &features) { int w = image.Shape().width; // image width int h = image.Shape().height; // image height // Create grayscale image used for Harris detection CFloatImage grayImage=ConvertToGray(image); // Apply a 7x7 gaussian blur to the grayscale image CFloatImage blurImage(w,h,1); Convolve(grayImage, blurImage, ConvolveKernel_7x7); // Transform matrices CTransform3x3 xform; CTransform3x3 trans1; CTransform3x3 rotate; CTransform3x3 scale; CTransform3x3 trans2; // Declare additional variables float pxl; // pixel value double mean, sq_sum, stdev; // variables for normailizing data set // This image represents the window around the feature you need to compute to store as the feature descriptor const int windowSize = 8; CFloatImage destImage(windowSize, windowSize, 1); for (vector<Feature>::iterator i = features.begin(); i != features.end(); i++) { Feature &f = *i; // Compute the transform from each pixel in the 8x8 image to sample from the appropriate // pixels in the 40x40 rotated window surrounding the feature trans1 = CTransform3x3::Translation(f.x, f.y); // translate window to feature point rotate = CTransform3x3::Rotation(f.angleRadians * 180.0 / PI); // rotate window by angle scale = CTransform3x3::Scale(5.0); // scale window by 5 trans2 = CTransform3x3::Translation(-windowSize/2, -windowSize/2); // translate window to origin // transform resulting from combining above transforms xform = trans1*scale*rotate*trans2; //Call the Warp Global function to do the mapping WarpGlobal(blurImage, destImage, xform, eWarpInterpLinear); // Resize data field for a 8x8 square window f.data.resize(windowSize * windowSize); // Find mean of window mean = 0; for (int y = 0; y < windowSize; y++) { for (int x = 0; x < windowSize; x++) { pxl = destImage.Pixel(x, y, 0); f.data[y*windowSize + x] = pxl; mean += pxl/(windowSize*windowSize); } } // Find standard deviation of window sq_sum = 0; for (int k = 0; k < windowSize*windowSize; k++) { sq_sum += (mean - f.data[k]) * (mean - f.data[k]); } stdev = sqrt(sq_sum/(windowSize*windowSize)); // Normalize window to have 0 mean and unit variance by subtracting // by mean and dividing by standard deviation for (int k = 0; k < windowSize*windowSize; k++) { f.data[k] = (f.data[k]-mean)/stdev; } } }