cv::Mat images::ellipseCrop(QGraphicsRectItem * rect) { cv::Rect myRoi(rect->rect().x(),rect->rect().y(),rect->rect().width(),rect->rect().height()); cv::Mat croppedImage; cv::Point center(rect->rect().x()+rect->rect().width()/2,rect->rect().y()+rect->rect().height()/2); cv::Size size(rect->rect().width()/2,rect->rect().height()/2); cv::Mat im1(matrix.rows, matrix.cols, CV_8UC1, cv::Scalar(255,255,255)); cv::Mat im2(matrix.rows, matrix.cols, CV_8UC1, cv::Scalar(0,0,0)); cv::ellipse( im2, center, size, 0, 0, 360, cv::Scalar( 255, 255, 255), -1, 8 ); cv::ellipse( im1, center, size, 0, 0, 360, cv::Scalar( 0, 0, 0), -1, 8 ); cv::bitwise_and(matrix,im2,croppedImage); cv::bitwise_xor(croppedImage,im1,croppedImage); return croppedImage(myRoi); }
int main( int argc, char** argv ) { /// Load an image cv::Mat src, greyIm, histeqIm; src = cv::imread( argv[1] ); if( !src.data ) { printf("Input file? No? ouuuupsss thooooorryyyyy\n"); return -1; } cv::Size s = src.size(); int rows = s.height; int cols = s.width; // Setup a rectangle to define your region of interest cv::Rect myROI(0, rows/2, cols, rows/2); // Crop the full image to that image contained by the rectangle myROI // Note that this doesn't copy the data cv::Mat croppedImage = src(myROI); cv::imwrite("output/1_low_half.jpg", croppedImage); cv::cvtColor(croppedImage, greyIm, cv::COLOR_BGR2GRAY); cv::Size crop_size = croppedImage.size(); int crop_rows = crop_size.height; int crop_cols = crop_size.width; cv::imwrite("output/2_grey_scale.jpg", greyIm); cv::equalizeHist( greyIm, histeqIm ); cv::imwrite("output/3_hist_eq.jpg", histeqIm); std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; // Reduce noise with kernel 3x3 cv::Mat blurIm; blur(histeqIm, blurIm, cv::Size(3,3)); cv::imwrite("output/4_blur.jpg", blurIm); // Canny detector cv::Mat edgesIm; Canny(blurIm, edgesIm, thresh, thresh*ratio, kernel_size); cv::imwrite("output/5_edge.jpg", edgesIm); // Find contours cv::findContours(edgesIm, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0,0)); // Approximate contours to polygons + get bounding rects and circles std::vector<std::vector<cv::Point> > contours_poly(contours.size()); std::vector<cv::Rect> boundRect(contours.size()); std::vector<cv::Point2f>center(contours.size()); std::vector<float>radius(contours.size()); for (int i = 0; i < contours.size(); i++) { cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true); boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i])); cv::minEnclosingCircle((cv::Mat)contours_poly[i], center[i], radius[i]); } // Draw contours int j=0; cv::Mat drawing = cv::Mat::zeros(edgesIm.size(), CV_8UC3); cv::Mat piece[5], hsvIm[5]; for (int i = 0; i < contours.size(); i++) { if (!((boundRect[i].height >= boundRect[i].width/5) && (boundRect[i].height <= boundRect[i].width/2) && boundRect[i].height<=crop_rows/4 && boundRect[i].width<=crop_cols/2 && boundRect[i].height>=crop_rows/10 && boundRect[i].width>=crop_cols/6)) continue; cv::Rect roi = boundRect[i]; piece[j] = croppedImage(roi); imwrite("output/contour"+std::to_string(j)+".jpg", piece[j]); j++; cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255)); cv::drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, cv::Point()); cv::rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0); //circle(drawing, center[i], (int)radius[i], color, 2, 8, 0); } imwrite("output/6_contours.jpg", drawing); int h_bins = 50; int s_bins = 60; int histSize[] = { h_bins, s_bins }; float h_ranges[] = { 0, 180 }; float s_ranges[] = { 0, 256 }; const float* ranges[] = { h_ranges, s_ranges }; int channels[] = { 0, 1 }; cv::Mat hist[5]; for (int i=0; i<j; i++){ cvtColor(piece[i], hsvIm[i], cv::COLOR_BGR2HSV); imwrite("output/hsvIm"+std::to_string(i)+".jpg", hsvIm[i]); calcHist( &hsvIm[i], 1, channels, cv::Mat(), hist[i], 2, histSize, ranges, true, false ); //normalize( hsvIm[i], hsvIm[i], 0, 1, cv::NORM_MINMAX, -1, cv::Mat() ); } return 0; }
/******************* 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; }
/******************* 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; }