void minmax( const cv::Mat& src, cv::Mat& min, cv::Mat& max, int velikost ) { // velikost - musí být liché číslo, minimálně 3 int stred = velikost/2; stred = MAX(1,stred); velikost = 2*stred+1; // zvětšíme obraz a okopírujeme krajní hodnoty do okrajů cv::Mat srcBorder; copyMakeBorder( src, srcBorder, stred, stred, stred, stred, cv::BORDER_REPLICATE ); // připravíme výstupní obraz min = cv::Mat( src.size(), src.type() ); max = cv::Mat( src.size(), src.type() ); // připravíme vektor k řazení prvků std::vector<uchar> buff(velikost*velikost); for( int j = 0; j < src.rows; ++j ) { for( int i = 0; i < src.cols; ++i ) { // připravíme vektor tak, aby jsme k němu mohli přistupovat jako k matici hodnot cv::Mat m(buff); // do matice nakopírujte hodnoty z okolí pro následné seřazení for(int y=0;y<velikost;++y) for(int x=0;x<velikost;++x){ buff[y*velikost+x] = srcBorder.at<uchar>(y+j,x+i); } // seřadíme hodnoty ve vektoru std::sort(buff.begin(), buff.end()); // výslednou hodnotu uložte do výstupního obrazu min.at<uchar>(j,i) = buff[0]; max.at<uchar>(j,i) = buff[velikost*velikost-1]; } } return; }
void MainWindow::on_actionLocal_threshold_triggered() { if(!activeMdiChild()) return; CvGlWidget *actCV = activeMdiChild(); cv::Mat paddedImage; int kSize = threshUI->kernelSize; int UIT = threshUI->localThresh; int top = kSize, bottom = kSize, left = kSize, right = kSize; int borderType = threshUI->borderType; //BORDER_REPLICATE BORDER_REFLECT101 copyMakeBorder(actCV->cvImage, paddedImage, top, bottom, left, right, borderType, Scalar(0)); int r = actCV->cvImage.rows; int c = actCV->cvImage.cols; // paddedImage.convertTo(paddedImage, CV_64FC1); // actCV->cvImage.convertTo(actCV->cvImage, CV_64FC1); cv::Mat t_im = Mat::zeros(r, c, CV_8UC1); cv::Mat sum; integral(actCV->cvImage, sum, CV_64FC1); for(int i = 0; i < r; i++){ for(int j = 0; j < c; j++){ float sum = 0; // int it = 0; //run the kernel now for(int u = -(kSize - 1)/2; u <= (kSize - 1)/2; u++) for(int v = -(kSize - 1)/2; v <=(kSize -1)/2; v++){ sum += (float)paddedImage.at<uchar>(i +kSize+ u,j +kSize+ v); } //threshold here; 7 is ok float t = (float)sum/(kSize*kSize) - 7; if((float)actCV->cvImage.at<uchar>(i, j) > t) t_im.at<uchar>(i, j) = 255; else t_im.at<uchar>(i, j) = 0; } } actCV->showImage(t_im); actCV->buildHistogram(); makeHistogram(); }
/* src: input image kernel: filter kernel return: convolution result */ Mat Dip2::spatialConvolution(Mat& src, Mat& kernel){ // TO DO !! Mat outputImage = src.clone(); int border = kernel.cols / 2; //assume it is symmetry Mat src_buf(src.rows + border*2, src.cols + border*2, src.depth()); //prepare for matrix with border copyMakeBorder(src, src_buf, border, border,border, border, BORDER_REPLICATE); //extend border by replicating rows and cols //flip kernel along x and y axis flip(kernel, kernel, -1); for (int y = border; y < src_buf.rows-border; y++){ for (int x = border; x < src_buf.cols-border; x++){ float convolution = 0.; for (int j = 0; j < kernel.rows; j++){ for (int i = 0; i < kernel.cols; i++){ convolution += src_buf.at<float>(y - (kernel.rows/2) + j, x - (kernel.cols/2) + i)*kernel.at<float>(j, i); } } outputImage.at<float>(y-border, x-border) = convolution; } } return outputImage; }
void nnor::hierarchicCharactersPadding(vector<vector<vector<Mat>>> chars) { int nnRows = 0; int nnCols = 0; for (int i = 0; i < chars.size(); i++) { for (int j = 0; j < chars[i].size(); j++) { for (int k = 0; k < chars[i][j].size(); k++) { chars[i][j][k] = autoCrop(chars[i][j][k]); if (chars[i][j][k].rows > nnRows) nnRows = chars[i][j][k].rows; if (chars[i][j][k].cols > nnCols) nnCols = chars[i][j][k].cols; } } } for (int i = 0; i < chars.size(); i++) { for (int j = 0; j < chars[i].size(); j++) { for (int k = 0; k < chars[i][j].size(); k++) { Mat character; chars[i][j][k].copyTo(character); int left = (nnCols - character.cols) / 2; int right = nnCols - left - character.cols; int top = (nnRows - character.rows) / 2; int bottom = nnRows - top - character.rows; copyMakeBorder(character, character, top, bottom, left, right, BORDER_CONSTANT, 255); chars[i][j][k] = character; } } } }
int ImageProcessor::test(const string &filename) { // Read the file Mat image = imread(filename, CV_LOAD_IMAGE_UNCHANGED); // Check for invalid input if(! image.data ) { qDebug() << "Could not open or find the image"; return -1; } Mat img_bin = cvtColorToBinary(image); copyMakeBorder( img_bin, img_bin, 1, 1, 1, 1, BORDER_CONSTANT, 0 ); vector<vector<Point> > contours = traceOutline(img_bin); vector<Point> approxCurve = decimateVerticies(contours.front(), 3); // draw contour for (size_t idx = 0; idx < contours.size(); idx++) { drawContours(img_bin, contours, idx, 50); } foreach(Point x, approxCurve) { img_bin.data[x.y * img_bin.cols + x.x] = 255; } // show output cv::imshow("Contours", img_bin); cv::waitKey(0); // success!! return 0; }
/** * rotates an image by the given angle * * rotateImage (jstring imagePath, jint angle) */ JNIEXPORT jint JNICALL Java_fr_ensicaen_panandroid_stitcher_StitcherWrapper_setPadding (JNIEnv* env, jobject obj, jstring imageSrc,jstring imageDst, jint paddingL, jint paddingT, jint paddingR, jint paddingB) { Mat matSrc; Mat matDst; const char* src = env->GetStringUTFChars(imageSrc, 0); const char* dst = env->GetStringUTFChars(imageDst, 0); matSrc = imread(src, CV_LOAD_IMAGE_COLOR); if(! matSrc.data ) // Check for invalid input { __android_log_print(ANDROID_LOG_ERROR, TAG, "Could not open or find the image %s", src); return -1; } /*if(strcmp(src, dst) == 0) { matDst = matSrc; }*/ copyMakeBorder( matSrc, matDst, paddingT, paddingB, paddingL, paddingR, BORDER_CONSTANT, 0 ); imwrite(dst, matDst); env->ReleaseStringUTFChars(imageSrc, src); env->ReleaseStringUTFChars(imageDst, dst); matSrc.release(); matDst.release(); return 0; }
// Agrega un borde de 1 px a la imagen binaria sólo si es necesario // retorna true si agregó borde bool Proxy::agregarBorde() { unsigned short y, x, xMax2; unsigned short yMax = imgBinaria.rows; unsigned short xMax = imgBinaria.cols; bool encontrado = false; uchar* fila; fila = imgBinaria.ptr<uchar>(0); // fila arriba for (x = 0 ; (x < xMax && !encontrado) ; ++x) { if (fila[x] == 0) encontrado = true; } if (!encontrado) { fila = imgBinaria.ptr<uchar>(yMax - 1); // fila abajo for (x = 0 ; (x < xMax && !encontrado) ; ++x) { if (fila[x] == 0) encontrado = true; } } if (!encontrado) { for (y = 1 ; (y < yMax && !encontrado) ; ++y) { if (imgBinaria.at<uchar>(y, 0) == 0) encontrado = true; } } if (!encontrado) { xMax2 = xMax - 1; for (y = 1 ; (y < yMax && !encontrado) ; ++y) { if (imgBinaria.at<uchar>(y, xMax2) == 0) encontrado = true; } } if (encontrado) { copyMakeBorder(imgBinaria, imgBinaria, 1, 1, 1, 1, BORDER_CONSTANT, 255); // agregamos borde de 1px para evitar errores iMapa->bordeAgregado = true; } return encontrado; }
bool OCRTess::detectAndRecog() { UMat grey = UMat::zeros(this->img.rows + 2, this->img.cols + 2, CV_8UC1); cvtColor(this->img.clone(), grey, COLOR_RGB2GRAY); vector<UMat> channels; channels.clear(); channels.push_back(grey); Mat m = 255 - grey.getMat(ACCESS_READ | ACCESS_WRITE); channels.push_back(m.getUMat(ACCESS_READ)); vector<vector<ERStat>> regions(2); regions[0].clear(); regions[1].clear(); switch (this->REGION) { case REG_CSER: { parallel_for_(Range(0, (int) channels.size()), Parallel_extractCSER(channels, regions, this->erf1, this->erf2)); break; } case REG_MSER: { vector<vector<Point> > contours; vector<Rect> bboxes; Ptr<MSER> mser = MSER::create(21, (int) (0.00002 * grey.cols * grey.rows), (int) (0.05 * grey.cols * grey.rows), 1, 0.7); mser->detectRegions(grey, contours, bboxes); if (contours.size() > 0) MSERsToERStats(grey, contours, regions); break; } default: { break; } } /*Text Recognition (OCR)*/ vector<vector<Vec2i> > nm_region_groups; vector<Rect> nm_boxes; switch (this->GROUP) { case 0: erGrouping(this->img, channels, regions, nm_region_groups, nm_boxes, ERGROUPING_ORIENTATION_HORIZ); break; case 1: default: erGrouping(this->img, channels, regions, nm_region_groups, nm_boxes, ERGROUPING_ORIENTATION_ANY, DIR + TR_GRP, 0.5); break; } if (!nm_boxes.size() || nm_boxes.size() > 1) return false; vector<string> words_detection; float min_confidence1 = 51.f, min_confidence2 = 60.f; vector<UMat> detections; for (int i = 0; i < (int) nm_boxes.size(); i++) { // rectangle(this->out, nm_boxes[i].tl(), nm_boxes[i].br(), Scalar(255, 255, 0), 3); UMat group_img = UMat::zeros(this->img.rows + 2, this->img.cols + 2, CV_8UC1); er_draw(channels, regions, nm_region_groups[i], group_img); group_img = group_img(nm_boxes[i]); copyMakeBorder(group_img.clone(), group_img, 15, 15, 15, 15, BORDER_CONSTANT, Scalar(0)); detections.push_back(group_img); } vector<string> outputs((int) detections.size()); vector<vector<Rect> > boxes((int) detections.size()); vector<vector<string> > words((int) detections.size()); vector<vector<float> > confidences((int) detections.size()); if (!detections.size() || detections.size() > 1) return false; for (int i = 0; i < (int) detections.size(); i = i + this->num) { Range r; if (i + this->num <= (int) detections.size()) r = Range(i, i + this->num); else r = Range(i, (int) detections.size()); parallel_for_(r, Parallel_OCR<OCRTesseract>(detections, outputs, boxes, words, confidences, this->ocrs)); } for (int i = 0; i < (int) detections.size(); i++) { outputs[i].erase(remove(outputs[i].begin(), outputs[i].end(), '\n'), outputs[i].end()); if (outputs[i].size() < 3) { continue; } for (int j = 0; j < (int) boxes[i].size(); j++) { boxes[i][j].x += nm_boxes[i].x - 15; boxes[i][j].y += nm_boxes[i].y - 15; if ((words[i][j].size() < 2) || (confidences[i][j] < min_confidence1) || ((words[i][j].size() == 2) && (words[i][j][0] == words[i][j][1])) || ((words[i][j].size() < 4) && (confidences[i][j] < min_confidence2)) || isRepetitive(words[i][j])) continue; words_detection.push_back(words[i][j]); // rectangle(this->out, boxes[i][j].tl(), boxes[i][j].br(), Scalar(255, 0, 255), 3); // Size word_size = getTextSize(words[i][j], FONT_HERSHEY_SIMPLEX, (double) scale_font, (int) (3 * scale_font), NULL); // rectangle(this->out, boxes[i][j].tl() - Point(3, word_size.height + 3), boxes[i][j].tl() + Point(word_size.width, 0), Scalar(255, 0, 255), -1); // putText(this->out, words[i][j], boxes[i][j].tl() - Point(1, 1), FONT_HERSHEY_SIMPLEX, scale_font, Scalar(255, 255, 255), (int) (3 * scale_font)); } } if (!words_detection.size() || words_detection.size() > 1) return false; return (words_detection[0].compare(WORD) == 0); }
// Fill the new column of node existence matrix using the last tau_w permutation and // cost matrices. Starting from the last permutation matrix, each new segment is connected // to one of the previous segments where pairwise segment matching cost is below the tau_m. // For each new segment, optimum match with previous segments defined by permutation matrix // and new segment is connected to the latest segment for which matching cost is below tau_m float SegmentTrack::fillNodeMap(const vector<vector<NodeSig> >& ns_vec) { int N = ns_vec.size(); //Number of the permutation matrices float matching_cost = 0; float smallest_matching_cost = 9999999; vector<Mat> P(N-1), C(N-1); //Create pairwise P and C matrices //Last frame is matched with each of last tau_w frames //and associated P and C matrices inserted into a vector //This step is requied for matching any nonmatched nodes for(int i = 2; i <= N; i++) { float match_score = gm->matchTwoImages(ns_vec[N-i], ns_vec.back(), P[N-i], C[N-i]); } //Expand M(node existence matrix) to fit new column copyMakeBorder(M,M,0,0,0,1,BORDER_CONSTANT,-1); //Place each segment into M matrix for(int s = 0; s < ns_vec.back().size(); s++) { int node_id = -1; //Node id represents new segment's id in existence map //Check last N frames(associated permutation matrices) //Find if any of previous segments matches with segment(i.e. matching cost // is below threshold) for(int i = 2; i <= N; i++) { int j = getPermuted(P[N-i],s); //Check matching cost if(j != -1 && C[N-i].at<float>(j,s) < params->seg_track_params.tau_m) { //return index of jth node in node existence map node_id = getIndexByCol(M, M.size().width-i, j); matching_cost = matching_cost + C[N-i].at<float>(j,s); break; } //If no matches are found, add smallest matching cost to total //matching cost if(j != -1 && smallest_matching_cost > C[N-i].at<float>(j,s)) { smallest_matching_cost = C[N-i].at<float>(j,s); } } // If there is no match if(node_id == -1) { //Add new row to M matrix and set last element with new id copyMakeBorder(M,M,0,1,0,0,BORDER_CONSTANT,-1); M.at<int>(M.size().height-1, M.size().width-1) = s; matching_cost = matching_cost + smallest_matching_cost; //Add new empty node to M_ns pair<NodeSig, int> new_node(ns_vec.back()[s], 1); M_ns.push_back(new_node); } else { M.at<int>(node_id, M.size().width-1) = s; //Update average node signatures SSGProc::updateNodeSig(M_ns[node_id], ns_vec.back()[s]); } } return matching_cost; }
Mat make_dft(const Mat& IRGB) { Mat I; cvtColor(IRGB, I, CV_RGB2GRAY); Mat padded; //expand input image to optimal size int m = getOptimalDFTSize(I.rows); int n = getOptimalDFTSize(I.cols); // on the border add zero values copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; Mat complexI; merge(planes, 2, complexI); // Add to the expanded another plane with zeros dft(complexI, complexI); // this way the result may fit in the source matrix // compute the magnitude and switch to logarithmic scale // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) magnitude(planes[0], planes[1], planes[0]); // planes[0] = magnitude Mat magI = planes[0]; magI += Scalar::all(1); // switch to logarithmic scale log(magI, magI); // crop the spectrum, if it has an odd number of rows or columns magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); // rearrange the quadrants of Fourier image so that the origin is at the image center int cx = magI.cols / 2; int cy = magI.rows / 2; Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right Mat tmp; // swap quadrants (Top-Left with Bottom-Right) q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) q2.copyTo(q1); tmp.copyTo(q2); normalize(magI, magI, 0, 1, CV_MINMAX); /* int lowThreshold = 100; int ratio = 3; int kernel_size = 3; Mat detected_edges; Mat gray; Mat sharpened; magI.convertTo(gray, CV_8U); cv::GaussianBlur(gray, sharpened, cv::Size(0, 0), 3); cv::addWeighted(gray, 1.5, sharpened, -0.5, 0, sharpened); sharpened.convertTo(magI, CV_32F);*/ return magI; }
template <typename PointT> double pcl::people::PersonClassifier<PointT>::evaluate (float height_person, float xc, float yc, PointCloudPtr& image) { if (SVM_weights_.empty ()) { PCL_ERROR ("[pcl::people::PersonClassifier::evaluate] SVM has not been set!\n"); return (-1000); } int height = floor((height_person * window_height_) / (0.75 * window_height_) + 0.5); // floor(i+0.5) = round(i) int width = floor((height_person * window_width_) / (0.75 * window_height_) + 0.5); int xmin = floor(xc - width / 2 + 0.5); int ymin = floor(yc - height / 2 + 0.5); double confidence; if (height > 0) { // If near the border, fill with black: PointCloudPtr box(new PointCloud); copyMakeBorder(image, box, xmin, ymin, width, height); // Make the image match the correct size (used in the training stage): PointCloudPtr sample(new PointCloud); resize(box, sample, window_width_, window_height_); // Convert the image to array of float: float* sample_float = new float[sample->width * sample->height * 3]; int delta = sample->height * sample->width; for (uint32_t row = 0; row < sample->height; row++) { for (uint32_t col = 0; col < sample->width; col++) { sample_float[row + sample->height * col] = ((float) ((*sample)(col, row).r))/255; //ptr[col * 3 + 2]; sample_float[row + sample->height * col + delta] = ((float) ((*sample)(col, row).g))/255; //ptr[col * 3 + 1]; sample_float[row + sample->height * col + delta * 2] = (float) (((*sample)(col, row).b))/255; //ptr[col * 3]; } } // Calculate HOG descriptor: pcl::people::HOG hog; float *descriptor = (float*) calloc(SVM_weights_.size(), sizeof(float)); hog.compute(sample_float, descriptor); // Calculate confidence value by dot product: confidence = 0.0; for(size_t i = 0; i < SVM_weights_.size(); i++) { confidence += SVM_weights_[i] * descriptor[i]; } // Confidence correction: confidence -= SVM_offset_; delete[] descriptor; delete[] sample_float; } else { confidence = std::numeric_limits<double>::quiet_NaN(); } return confidence; }
void PhaseCorrelation::controller(const sensor_msgs::ImageConstPtr& msg) { //Transform the image to opencv format cv_bridge::CvImagePtr cv_ptr; try { cv_ptr = cv_bridge::toCvCopy(msg, enc::BGR8); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } Mat image = cv_ptr->image; imshow("image", image); waitKey(1); //Transform image to grayscale cvtColor(image, image2_in, CV_RGB2GRAY); //Image2 is the newest image, the one we get from this callback //image1 is the image2 from the last callback (we use the one that already has the dft applied. Mat image1_dft = last_image_dft; //Image2, preparation and dft Mat padded2; //expand input image to optimal size int m2 = getOptimalDFTSize( image2_in.rows ); int n2 = getOptimalDFTSize( image2_in.cols ); // on the border add zero values copyMakeBorder(image2_in, padded2, 0, m2 - image2_in.rows, 0, n2 - image2_in.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes2[] = {Mat_<float>(padded2), Mat::zeros(padded2.size(), CV_32F)}; Mat image2,image2_dft; merge(planes2, 2, image2); // Add to the expanded another plane with zeros dft(image2, image2_dft); //Image2 will be image1 on next iteration last_image_dft=image2_dft; if( !first){ //obtain the cross power spectrum c(u,v)=F(u,v)·G*(u,v)/abs(F(u,v)·G*(u,v)) Mat divident, divisor, cross_power_spec, trans_mat; mulSpectrums(image1_dft, image2_dft, divident, 0, true); //=F(u,v)·G*(u,v) --> multiply the result of a dft //divident-> where it stores the result. // flags=0. conj=true, because i want the image2 to be the complex conjugate. divisor=abs(divident); divide(divident, divisor, cross_power_spec, 1); //dft of the cross_power_spec dft(cross_power_spec, trans_mat, DFT_INVERSE); //Normalize the trans_mat so that all the values are between 0 and 1 normalize(trans_mat, trans_mat, NORM_INF); //Split trans_mat in it's real and imaginary parts vector<Mat> trans_mat_vector; split(trans_mat, trans_mat_vector); Mat trans_mat_real = trans_mat_vector.at(0); Mat trans_mat_im = trans_mat_vector.at(1); imshow("trans_mat_real", trans_mat_real); waitKey(1); //Look for maximum value and it's location on the trans_mat_real matrix double* max_value; Point* max_location; double max_val; Point max_loc; max_value = &max_val; max_location = &max_loc; minMaxLoc(trans_mat_real, NULL, max_value, NULL, max_location); ROS_INFO_STREAM("max_value: " << max_val << " - " << "max_location: " << max_loc); int pixel_x, pixel_y; if(max_loc.x < (image2.cols/2) && max_loc.y < (image2.rows/2)){ // top-left quadrant ROS_INFO_STREAM(" top - left quadrant"); pixel_x = max_loc.x; pixel_y = - max_loc.y; } if(max_loc.x > (image2.cols/2) && max_loc.y > (image2.rows/2)){ // lower-right quadrant ROS_INFO_STREAM(" lower - right quadrant"); pixel_x = - image2.cols + max_loc.x; pixel_y = + image2.rows - max_loc.y; } if(max_loc.x > (image2.cols/2) && max_loc.y < (image2.rows/2)){ // top-right quadrant ROS_INFO_STREAM(" top - right quadrant"); pixel_x = - image2.cols + max_loc.x; pixel_y = - max_loc.y; } if(max_loc.x < (image2.cols/2) && max_loc.y > (image2.rows/2)){ // lower-left quadrant ROS_INFO_STREAM(" lower - left quadrant"); pixel_x = max_loc.x; pixel_y = image2.rows - max_loc.y; } //Add the new displacement to the accumulated pixels_x = pixels_x + pixel_x; pixels_y = pixels_y + pixel_y; ROS_INFO_STREAM("pixels_x: " << pixels_x << " - " << "pixel_y: " << pixels_y); //------ transform pixels to mm --------- //To get the focal lenght: if (first){ Mat cameraMatrix(3, 3, CV_32F); cameraMatrix.at<float>(0,0)= 672.03175; //Values from the camera matrix are from the visp calibration cameraMatrix.at<float>(0,1) = 0.00000; cameraMatrix.at<float>(0,2) = 309.39349; cameraMatrix.at<float>(1,0) = 0.00000; cameraMatrix.at<float>(1,1) = 673.05595; cameraMatrix.at<float>(1,2) = 166.52006; cameraMatrix.at<float>(2,0) = 0.00000; cameraMatrix.at<float>(2,1) = 0.00000; cameraMatrix.at<float>(2,2) = 1.00000; double apertureWidth, apertureHeight, fovx, fovy, focalLength, aspectRatio; Point2d principalPoint; calibrationMatrixValues(cameraMatrix, image.size(), apertureWidth, apertureHeight, fovx, fovy, focalLength, principalPoint, aspectRatio); ROS_INFO_STREAM("focalLength: " << focalLength); fl = focalLength; first=false; } float mov_x = pixel_x/fl*h; float mov_y = pixel_y/fl*h; mov_x_acc = mov_x_acc + mov_x; mov_y_acc = mov_y_acc + mov_y; ROS_INFO_STREAM("mov_x: " << mov_x << " - mov_y: " << mov_y); ROS_INFO_STREAM("mov_x_acc: " << mov_x_acc << " - mov_y_acc: " << mov_y_acc); } }
char detectBlueBlock(Mat image) { int T=15; //面积与边长之比的阈值 ColorHistogram hc; MatND colorhist = hc.getHueHistogram(image); //遍历直方图数据 //hc.getHistogramStat(colorhist); /* Mat histImg = hc.getHistogramImage(colorhist); namedWindow("BlueBlockHistogram"); imshow("BlueBlockHistogram", histImg);*/ Mat thresholded, thresholded1, thresholded2, thresholded3; threshold(hc.v[0], thresholded1, 100, 255, 1); threshold(hc.v[0], thresholded2, 124, 255, 0); threshold(hc.v[1], thresholded3, 125, 255, 1); //变成黑色 thresholded = thresholded1+thresholded2+thresholded3; //imshow("1", thresholded1); //imshow("2", thresholded2); //imshow("3", thresholded3); //namedWindow("BlueBlockBinary"); //imshow("BlueBlockBinary", thresholded); int top = (int) (0.05*thresholded.rows); int bottom = (int) (0.05*thresholded.rows); int left = (int) (0.05*thresholded.cols); int right = (int) (0.05*thresholded.cols); Scalar value = Scalar( 255 ); copyMakeBorder( thresholded, thresholded, top, bottom, left, right, 0, value ); /* Mat eroded; erode(thresholded, eroded, Mat()); namedWindow("ErodedImage"); imshow("ErodedImage", eroded); Mat dilated; erode(thresholded, dilated, Mat()); namedWindow("DilatedImage"); imshow("DilatedImage", dilated);*/ //闭运算 Mat closed; morphologyEx(thresholded, closed, MORPH_CLOSE, Mat()); //namedWindow("ClosedImage"); //imshow("ClosedImage", closed); vector<vector<Point>>contours; findContours(closed, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); //筛选不合格轮廓 int cmin = 100; //最小轮廓长度 vector<vector<Point>>::const_iterator itc = contours.begin(); while (itc != contours.end()) { if (itc->size()<cmin) itc = contours.erase(itc); else itc++; } Mat result(closed.size(), CV_8U, Scalar(255)); double area, length, p; double a[2] = {0,0}; cout << "Size=" << contours.size() << endl; for ( int i=0; i<contours.size(); i++) { area = abs(contourArea( contours[i] )); length = abs(arcLength( contours[i], true )); p = area/length; if (p > a[0]) { a[1] = a[0]; a[0] = p; } else if (p > a[1]) a[1] = p; cout << "Area=" << area << " " << "Length=" << length << " " << "Property=" << p << endl; } drawContours(result, contours, -1, Scalar(0), 1); //namedWindow("DrawContours"); //imshow("DrawContours", result); cout << "Property=" << a[1] << endl; //waitKey(); if (a[1] > T) return BLUEBLOCK; else return NOTHING; }
void VideoCorrect::correctImage(Mat& inputFrame, Mat& outputFrame, bool developerMode){ resize(inputFrame, inputFrame, CAMERA_RESOLUTION); inputFrame.copyTo(img); //Convert to YCbCr color space cvtColor(img, ycbcr, CV_BGR2YCrCb); //Skin color thresholding inRange(ycbcr, Scalar(0, 150 - Cr, 100 - Cb), Scalar(255, 150 + Cr, 100 + Cb), bw); if(IS_INITIAL_FRAME){ face = detectFaces(img); if(face.x != 0){ lastFace = face; } else{ outputFrame = img; return; } prevSize = Size(face.width/2, face.height/2); head = Mat::zeros(bw.rows, bw.cols, bw.type()); ellipse(head, Point(face.x + face.width/2, face.y + face.height/2), prevSize, 0, 0, 360, Scalar(255,255,255,0), -1, 8, 0); if(face.x > 0 && face.y > 0 && face.width > 0 && face.height > 0 && (face.x + face.width) < img.cols && (face.y + face.height) < img.rows){ img(face).copyTo(bestImg); } putText(img, "Give your best pose!", Point(face.x, face.y), CV_FONT_HERSHEY_SIMPLEX, 0.4, Scalar(255,255,255,0), 1, CV_AA); } firstFrameCounter--; if(face.x == 0) //missing face prevention face = lastFace; //Mask the background out bw &= head; //Compute more accurate image moments after background removal m = moments(bw, true); angle = (atan((2*m.nu11)/(m.nu20-m.nu02))/2)*180/PI; center = Point(m.m10/m.m00,m.m01/m.m00); //Smooth rotation (running average) bufferCounter++; rotationBuffer[ bufferCounter % SMOOTHER_SIZE ] = angle; smoothAngle += (angle - rotationBuffer[(bufferCounter + 1) % SMOOTHER_SIZE]) / SMOOTHER_SIZE; //Expand borders copyMakeBorder( img, img, BORDER_EXPAND, BORDER_EXPAND, BORDER_EXPAND, BORDER_EXPAND, BORDER_REPLICATE, Scalar(255,255,255,0)); if(!IS_INITIAL_FRAME){ //Rotate the image to correct the leaning angle rotateImage(img, smoothAngle); //After rotation detect faces face = detectFaces(img); if(face.x != 0) lastFace = face; //Create background mask around the face head = Mat::zeros(bw.rows, bw.cols, bw.type()); ellipse(head, Point(face.x - BORDER_EXPAND + face.width/2, face.y -BORDER_EXPAND + face.height/2), prevSize, 0, 0, 360, Scalar(255,255,255,0), -1, 8, 0); //Draw a rectangle around the face //rectangle(img, face, Scalar(255,255,255,0), 1, 8, 0); //Overlay the ideal pose if(replaceFace && center.x > 0 && center.y > 0){ center = Point(face.x + face.width/2, face.y + face.width/2); overlayImage(img, bestImg, center, smoothSize); } } else{ face.x += BORDER_EXPAND; //position alignment after border expansion (not necessary if we detect the face after expansion) face.y += BORDER_EXPAND; } //Smooth ideal image size (running average) sizeBuffer[ bufferCounter % SMOOTHER_SIZE ] = face.width; smoothSize += (face.width - sizeBuffer[(bufferCounter + 1) % SMOOTHER_SIZE]) / SMOOTHER_SIZE; //Get ROI center = Point(face.x + face.width/2, face.y + face.width/2); roi = getROI(img, center); if(roi.x > 0 && roi.y > 0 && roi.width > 0 && roi.height > 0 && (roi.x + roi.width) < img.cols && (roi.y + roi.height) < img.rows){ img = img(roi); } //Resize the final image resize(img, img, CAMERA_RESOLUTION); if(developerMode){ Mat developerScreen(img.rows, img.cols + inputFrame.cols + bw.cols, CV_8UC3); Mat left(developerScreen, Rect(0, 0, img.size().width, img.size().height)); img.copyTo(left); Mat center(developerScreen, Rect(img.cols, 0, inputFrame.cols, inputFrame.rows)); inputFrame.copyTo(center); cvtColor(bw, bw, CV_GRAY2BGR); Mat right(developerScreen, Rect(img.size().width + inputFrame.size().width, 0, bw.size().width, bw.size().height)); bw.copyTo(right); Mat rightmost(developerScreen, Rect(img.size().width + inputFrame.size().width + bw.size().width - bestImg.size().width, 0, bestImg.size().width, bestImg.size().height)); bestImg.copyTo(rightmost); outputFrame = developerScreen; } else{ outputFrame = img; } }
void CV_BilateralFilterTest::reference_bilateral_filter(const Mat &src, Mat &dst, int d, double sigma_color, double sigma_space, int borderType) { int cn = src.channels(); int i, j, k, maxk, radius; double minValSrc = -1, maxValSrc = 1; const int kExpNumBinsPerChannel = 1 << 12; int kExpNumBins = 0; float lastExpVal = 1.f; float len, scale_index; Size size = src.size(); dst.create(size, src.type()); CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && src.type() == dst.type() && src.size() == dst.size() && src.data != dst.data ); if( sigma_color <= 0 ) sigma_color = 1; if( sigma_space <= 0 ) sigma_space = 1; double gauss_color_coeff = -0.5/(sigma_color*sigma_color); double gauss_space_coeff = -0.5/(sigma_space*sigma_space); if( d <= 0 ) radius = cvRound(sigma_space*1.5); else radius = d/2; radius = MAX(radius, 1); d = radius*2 + 1; // compute the min/max range for the input image (even if multichannel) minMaxLoc( src.reshape(1), &minValSrc, &maxValSrc ); if(std::abs(minValSrc - maxValSrc) < FLT_EPSILON) { src.copyTo(dst); return; } // temporary copy of the image with borders for easy processing Mat temp; copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); patchNaNs(temp); // allocate lookup tables vector<float> _space_weight(d*d); vector<int> _space_ofs(d*d); float* space_weight = &_space_weight[0]; int* space_ofs = &_space_ofs[0]; // assign a length which is slightly more than needed len = (float)(maxValSrc - minValSrc) * cn; kExpNumBins = kExpNumBinsPerChannel * cn; vector<float> _expLUT(kExpNumBins+2); float* expLUT = &_expLUT[0]; scale_index = kExpNumBins/len; // initialize the exp LUT for( i = 0; i < kExpNumBins+2; i++ ) { if( lastExpVal > 0.f ) { double val = i / scale_index; expLUT[i] = (float)std::exp(val * val * gauss_color_coeff); lastExpVal = expLUT[i]; } else expLUT[i] = 0.f; } // initialize space-related bilateral filter coefficients for( i = -radius, maxk = 0; i <= radius; i++ ) for( j = -radius; j <= radius; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); if( r > radius ) continue; space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn); } for( i = 0; i < size.height; i++ ) { const float* sptr = (const float*)(temp.data + (i+radius)*temp.step) + radius*cn; float* dptr = (float*)(dst.data + i*dst.step); if( cn == 1 ) { for( j = 0; j < size.width; j++ ) { float sum = 0, wsum = 0; float val0 = sptr[j]; for( k = 0; k < maxk; k++ ) { float val = sptr[j + space_ofs[k]]; float alpha = (float)(std::abs(val - val0)*scale_index); int idx = cvFloor(alpha); alpha -= idx; float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); sum += val*w; wsum += w; } dptr[j] = (float)(sum/wsum); } } else { assert( cn == 3 ); for( j = 0; j < size.width*3; j += 3 ) { float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; for( k = 0; k < maxk; k++ ) { const float* sptr_k = sptr + j + space_ofs[k]; float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; float alpha = (float)((std::abs(b - b0) + std::abs(g - g0) + std::abs(r - r0))*scale_index); int idx = cvFloor(alpha); alpha -= idx; float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx])); sum_b += b*w; sum_g += g*w; sum_r += r*w; wsum += w; } wsum = 1.f/wsum; b0 = sum_b*wsum; g0 = sum_g*wsum; r0 = sum_r*wsum; dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0; } } } }
/** * The predicted sharp edge gradient ∇I^s is used as a spatial prior to guide * the recovery of a coarse version of the latent image. * Objective function: E(I) = ||I ⊗ k - B||² + λ||∇I - ∇I^s||² * * @param blurred blurred grayvalue image (B) * @param kernel energy presserving kernel (k) * @param selectionGrads gradients of selected edges (x and y direction) (∇I^s) * @param latent resulting image (I) * @param weight λ, default is 2.0e-3 (weight from paper) */ void coarseImageEstimation(Mat blurred, const Mat& kernel, const array<Mat,2>& selectionGrads, Mat& latent, const float weight = 2.0e-3) { assert(kernel.type() == CV_32F && "works with energy preserving float kernel"); assert(blurred.type() == CV_8U && "works with gray valued blurred image"); // convert grayvalue image to float and normalize it to [0,1] blurred.convertTo(blurred, CV_32F); blurred /= 255.0; // fill kernel with zeros to get to the blurred image size // it's important to use BORDER_ISOLATED flag if the kernel is an ROI of a greater image! Mat pkernel; copyMakeBorder(kernel, pkernel, 0, blurred.rows - kernel.rows, 0, blurred.cols - kernel.cols, BORDER_CONSTANT, Scalar::all(0)); // using sobel filter as gradients dx and dy Mat sobelx = Mat::zeros(blurred.size(), CV_32F); sobelx.at<float>(0,0) = -1; sobelx.at<float>(0,1) = 1; Mat sobely = Mat::zeros(blurred.size(), CV_32F); sobely.at<float>(0,0) = -1; sobely.at<float>(1,0) = 1; // ____ ______ ______ // ( F(k) * F(B) + λ * (F(∂_x) * F(∂_x I^s) + F(∂_y) * F(∂_y I^s)) ) // I = F^-1 * ( --------------------------------------------------------------- ) // ( ____ ______ ______ ) // ( F(k) * F(k) + λ * (F(∂_x) * F(∂_x) + F(∂_y) * F(∂_y)) ) // where * is pointwise multiplication // // here: F(k) = k // F(∂_x I^s) = xS // F(∂_y I^s) = yS // F(∂_x) = dx // F(∂_y) = dy // F(B) = B // compute DFT (withoud padding) // the result are stored as 2 channel matrices: Re(FFT(I)), Im(FFT(I)) Mat K, xS, yS, B, Dx, Dy; deblur::dft(pkernel, K); deblur::dft(selectionGrads[0], xS); deblur::dft(selectionGrads[1], yS); deblur::dft(blurred, B); deblur::dft(sobelx, Dx); deblur::dft(sobely, Dy); // weight from paper complex<float> we(weight, 0.0); // latent image in fourier domain Mat I = Mat::zeros(xS.size(), xS.type()); // pointwise computation of I for (int x = 0; x < xS.cols; x++) { for (int y = 0; y < xS.rows; y++) { // complex entries at the current position complex<float> b(B.at<Vec2f>(y, x)[0], B.at<Vec2f>(y, x)[1]); complex<float> k(K.at<Vec2f>(y, x)[0], K.at<Vec2f>(y, x)[1]); complex<float> xs(xS.at<Vec2f>(y, x)[0], xS.at<Vec2f>(y, x)[1]); complex<float> ys(yS.at<Vec2f>(y, x)[0], yS.at<Vec2f>(y, x)[1]); complex<float> dx(Dx.at<Vec2f>(y, x)[0], Dx.at<Vec2f>(y, x)[1]); complex<float> dy(Dy.at<Vec2f>(y, x)[0], Dy.at<Vec2f>(y, x)[1]); // compute current point of latent image in fourier domain complex<float> i = (conj(k) * b + we * (conj(dx) * xs + conj(dy) * ys)) / (conj(k) * k + we * (conj(dx) * dx + conj(dy) * dy)); I.at<Vec2f>(y, x) = { real(i), imag(i) }; } } // compute inverse DFT of the latent image dft(I, latent, DFT_INVERSE | DFT_REAL_OUTPUT); // threshold the result because it has large negative and positive values // which would result in a very grayish image threshold(latent, latent, 0.0, -1, THRESH_TOZERO); // swap slices of the result // because the image is shifted to the upper-left corner (why??) int x = latent.cols; int y = latent.rows; int hs1 = (kernel.cols - 1) / 2; int hs2 = (kernel.rows - 1) / 2; // create rects per image slice // __________ // | | | // | 0 | 1 | // | | | // |------|---| // | 2 | 3 | // |______|___| // // rect gets the coordinates of the top-left corner, width and height Mat q0(latent, Rect(0, 0, x - hs1, y - hs2)); // Top-Left Mat q1(latent, Rect(x - hs1, 0, hs1, y - hs2)); // Top-Right Mat q2(latent, Rect(0, y - hs2, x - hs1, hs2)); // Bottom-Left Mat q3(latent, Rect(x - hs1, y - hs2, hs1, hs2)); // Bottom-Right Mat latentSwap; cv::hconcat(q3, q2, latentSwap); Mat tmp; cv::hconcat(q1, q0, tmp); cv::vconcat(latentSwap, tmp, latentSwap); // convert result to uchar image convertFloatToUchar(latentSwap, latent); assert(blurred.size() == latent.size() && "Something went wrong - latent and blurred size has to be equal"); }
bool SpatialAverageSpotter::train(string dirPath) { int count=0; vector<vector<tuple<int,Point2f> > > features; featureAverages.resize(codebook->size()); for (int i =0; i<codebook->size(); i++) featureAverages[i]=Mat(BASE_SIZE,BASE_SIZE,CV_32F,Scalar(0)); DIR *dir; struct dirent *ent; if ((dir = opendir (dirPath.c_str())) != NULL) { /* print all the files and directories within directory */ // Mat img; while ((ent = readdir (dir)) != NULL) { string fileName(ent->d_name); // cout << "examining " << fileName << endl; if (fileName[0] == '.' || fileName[fileName.size()-1]!='G') continue; Mat img = imread(dirPath+fileName, CV_LOAD_IMAGE_GRAYSCALE); // resize(img,img,Size(0,0),2,2); threshold(img,img,120.0,255,THRESH_BINARY); // windowWidth += img.cols; // windowHeight += img.rows; // int avg=0; // for (int x=0; x<img.cols; x++) // for (int y=0; y<img.rows; y++) // avg += (int)img.at<unsigned char>(y,x); //// cout << "avg="<<avg<<"/"<<img.cols*img.rows<<" = "<<avg/(img.cols*img.rows)<<endl; // avg /= img.cols*img.rows; resize(img,img,Size(PRE_BASE_SIZE,PRE_BASE_SIZE*((0.0+img.rows)/img.cols))); copyMakeBorder( img, img, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_CONSTANT, 255 ); assert(img.cols > 1 && img.rows > 1); adjustedTrainingImages.push_back(img.clone()); Point2f centerOfMass = findCenterOfMass(img); int offsetx=(img.cols/2)-centerOfMass.x; int offsety=(img.rows/2)-centerOfMass.y; translateImg(img,offsetx,offsety); vector<KeyPoint> keypoints; Mat desc; detectKeypoints( img,keypoints, desc); Mat out; cvtColor(img,out,CV_GRAY2RGB); circle(out,centerOfMass,1,Scalar(0,0,255)); features.resize(count+1); //double scaling = BASE_SIZE/img for (int r=0; r<desc.rows; r++) { int f = codebook->quantize(desc.row(r)); Point2f offsetPoint(keypoints[r].pt.x - centerOfMass.x, keypoints[r].pt.y - centerOfMass.y); features[count].push_back(make_tuple(f,offsetPoint));//we're ignoring the keypoint scale.. // circle(out,keypoints[r].pt,keypoints[r].size,Scalar(colorTable[f])); Rect rec(keypoints[r].pt.x-(keypoints[r].size/2),keypoints[r].pt.y-(keypoints[r].size/2),keypoints[r].size,keypoints[r].size); rectangle(out,rec,Scalar(colorTable[f])); } guassColorIn(features[count]); imshow("learning keypoints",out); cout << "image "<<count<<endl; waitKey(5); count++; // img.release(); } closedir (dir); } else { /* could not open directory */ perror (""); return false; } //We now step through adjusting the scales of the various images so the guass coloring is maximized //But we may still want to look at tfidf to see which ones should be weighted more, etc. maximizeAlignment(features); float max=0; float min =99999; float avg_max=0; int firstx=9999; int lastx=0; int firsty=9999; int lasty=0; for (int f=0; f<codebook->size(); f++) { float local_max=0; bool hitFirst=false; for (int x=0; x<featureAverages[f].cols; x++) for (int y=0; y<featureAverages[f].rows; y++) { float val = featureAverages[f].at<float>(y,x); if (val > 300 || val < -300) cout << "val (" << x <<","<<y<<") " << val << endl; if (val>max) max=val; if (val<min) min=val; if (val>local_max) local_max=val; if (val>WINDOW_THRESH) { if (!hitFirst) { hitFirst=true; if (x<firstx) firstx=x; if (y<firsty) firsty=y; } if (x>lastx) lastx=x; if (y>lasty) lasty=y; } } avg_max+=local_max; } // penalty=min+(max-min)*.2; avg_max /= codebook->size(); penalty=avg_max*.15;//.2 // windowWidth/=count; // windowHeight/=count; windowWidth = lastx-firstx; windowHeight = lasty-firsty; cout << "window size is "<<windowWidth<<"x"<<windowHeight<<endl; //show averages showAverages(); return true; }
int main(int argc, char **argv){ int opcion; //Opcion para el getopt int vflag=0, rflag=0, nflag=0, glfag=0, iflag=0, mflag=0, oflag=0; //Flags para el getopt float r=0.5, g=1.0; int n=2; string nombreImagen; string nombreMascara; string nombreSalida = "output.png"; Mat imagen, padded, complexImg, filter, filterAux, imagenSalida, filterSalida, imagenFrecuencias, imagenFrecuenciasSinOrden, imagenHSV; Mat complexAux; Mat salida; Mat imagenPasoBaja; Mat mascara; vector<Mat> canales; while((opcion=getopt(argc, argv, "vr:n:g:i:o:m:")) !=-1 ){ switch(opcion){ case 'v': vflag=1; break; case 'r': rflag=1; r=atof(optarg); if(r<0 || r>1){ cout << "Valor de 'r' introducido invalido" << endl; exit(-1); } break; case 'n': nflag=1; n = atoi(optarg); if(n<0 || n>10){ cout << "Valor de 'n' introducido invalido" << endl; exit(-1); } break; case 'g': glfag=1; g = atof(optarg); if(g<0.0 || g>5.0){ cout << "Valor de 'g' introducido invalido" << endl; exit(-1); } break; case 'i': iflag=1; nombreImagen = optarg; break; case 'm': mflag=1; nombreMascara=optarg; break; case 'o': oflag=1; nombreSalida=optarg; break; case '?': //Algo ha ido mal help(); exit(-1); break; default: help(); exit(-1); break; } } //Primero cargaremos la imagen if(iflag==1){ imagen = imread(nombreImagen, CV_LOAD_IMAGE_ANYDEPTH); if(imagen.empty()){ cout << "Imagen especificada invalida" << endl; exit(-1); }else{ cout << "Imagen cargada con exito" << endl; if(vflag==1){ namedWindow("Imagen", CV_WINDOW_AUTOSIZE); imshow("Imagen", imagen); waitKey(0); destroyWindow("Imagen"); } } }else{ cout << "La imagen es necesaria" << endl; exit(-1); } //Calculamos r r=(r)*(sqrt(pow((imagen.rows),2.0)+pow((imagen.cols),2.0))/2); int M = getOptimalDFTSize(imagen.rows); int N = getOptimalDFTSize(imagen.cols); //Miramos si tiene mascara para cargarla if(mflag==1){ //Cargamos la mascara mascara = imread(nombreMascara, 0); if(mascara.empty()){ cout << "Mascara especificada invalida" << endl; exit(-1); }else{ cout << "Mascara cargada con exito" << endl; } } //Ahora miramos los canales para hacer cosas distintas dependiendo if(imagen.channels()==1){ //Imagen monocromatica imagen.convertTo(imagenPasoBaja,CV_32F, 1.0/255.0); copyMakeBorder(imagenPasoBaja, padded, 0, M-imagenPasoBaja.rows, 0, N - imagenPasoBaja.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; merge(planes, 2, complexImg); dft(complexImg, complexImg); filter = complexImg.clone(); filterAux = complexImg.clone(); complexAux = complexImg.clone(); shiftDFT(complexImg); shiftDFT(complexAux); butterworth(filter, r, n); butterworth(filterAux, r, 0); mulSpectrums(complexImg, filter, complexImg, 0); mulSpectrums(complexAux, filterAux, complexAux, 0); shiftDFT(complexImg); shiftDFT(complexAux); //Falta hacer lo de poder mostrarla imagenFrecuencias = create_spectrum(complexImg); imagenFrecuenciasSinOrden = create_spectrum(complexAux); //Hacemos la inversa idft(complexImg, complexImg, DFT_SCALE); split(complexImg, planes); normalize(planes[0], imagenSalida, 0, 1, CV_MINMAX); split(filter, planes); normalize(planes[0], filterSalida, 0, 1, CV_MINMAX); salida = imagenPasoBaja.clone(); if(mflag==1){ //Con mascara procesaremos pixel por pixel //Recorremos la imagen for(int i=0; i<imagen.rows; i++){ for(int j=0; j<imagen.cols;j++){ if(mascara.at<uchar>(i,j)!=0){ salida.at<float>(i,j) = (g+1)*(imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } }else{ //Sin mascara lo haremos de forma inmediata for(int i=0; i<imagen.rows; i++){ for(int j=0; j<imagen.cols;j++){ salida.at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } salida.convertTo(salida, CV_8U, 255.0, 0.0); if(vflag==1){ imshow("Imagen final", salida); imshow("Filtro Butterworth", filterSalida); imshow("Espectro", imagenFrecuencias); imshow("Espectro de imagen sin orden", imagenFrecuenciasSinOrden); waitKey(0); } }else{ //Spliteamos la imagen en canales cvtColor(imagen, imagenHSV, CV_BGR2HSV); split(imagenHSV, canales); Mat temporal; canales[2].convertTo(imagenPasoBaja, CV_32F, 1.0/255.0); copyMakeBorder(imagenPasoBaja, padded, 0, M-imagenPasoBaja.rows, 0, N - imagenPasoBaja.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; merge(planes, 2, complexImg); dft(complexImg, complexImg); filter = complexImg.clone(); shiftDFT(complexImg); butterworth(filter, r, n); mulSpectrums(complexImg, filter, complexImg, 0); shiftDFT(complexImg); //Falta hacer lo de poder mostrarla imagenFrecuencias = create_spectrum(complexImg); //Hacemos la inversa idft(complexImg, complexImg, DFT_SCALE); split(complexImg, planes); normalize(planes[0], imagenSalida, 0, 1, CV_MINMAX); split(filter, planes); normalize(planes[0], filterSalida, 0, 1, CV_MINMAX); Mat salida = imagen.clone(); canales[2] = imagenPasoBaja.clone(); if(mflag==1){ //Con mascara for(int i=0; i<canales[2].rows; i++){ for(int j=0; j<canales[2].cols;j++){ if(mascara.at<uchar>(i,j)!=0){ canales[2].at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } }else{ //Sin mascara for(int i=0; i<canales[2].rows; i++){ for(int j=0; j<canales[2].cols;j++){ canales[2].at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } canales[2].convertTo(canales[2], CV_8U, 255.0, 0.0); merge(canales, salida); cvtColor(salida, salida, CV_HSV2BGR); salida.convertTo(salida, CV_8U, 255.0, 0.0); if(vflag==1){ imshow("Imagen final", salida); imshow("Filtro Butterworth", filterSalida); imshow("Espectro", imagenFrecuencias); imshow("Espectro de imagen sin orden", imagenFrecuenciasSinOrden); waitKey(0); } } //Y escribimos la imagen a fichero imwrite(nombreSalida, salida); return 0; }
int main() { // A gray image cv::Mat_<float> img = cv::imread("Image4_1.png", CV_LOAD_IMAGE_GRAYSCALE); // Load image // cv::Mat_<float> img = cv::imread(argv[1], cv::IMREAD_GRAYSCALE); // Get original size int wxOrig = img.cols; int wyOrig = img.rows; int m = cv::getOptimalDFTSize( 2*wyOrig ); int n = cv::getOptimalDFTSize( 2*wxOrig ); copyMakeBorder(img, img, 0, m - wyOrig, 0, n - wxOrig, cv::BORDER_CONSTANT, cv::Scalar::all(0)); // Get padded image size const int wx = img.cols, wy = img.rows; const int cx = wx/2, cy = wy/2; std::cout << wxOrig << " " << wyOrig << std::endl; std::cout << wx << " " << wy << std::endl; std::cout << cx << " " << cy << std::endl; // Compute DFT of image cv::Mat_<float> imgs[] = {img.clone(), cv::Mat_<float>::zeros(wy, wx)}; cv::Mat_<cv::Vec2f> img_dft; cv::merge(imgs, 2, img_dft); cv::dft(img_dft, img_dft); // Shift to center dftshift(img_dft); // Used for visualization only cv::Mat_<float> magnitude, phase; cv::split(img_dft, imgs); cv::cartToPolar(imgs[0], imgs[1], magnitude, phase); magnitude = magnitude + 1.0f; cv::log(magnitude, magnitude); cv::normalize(magnitude, magnitude, 0, 1, CV_MINMAX); cv::imwrite("img_dft.png", magnitude * 255); // cv::imshow("img_dft", magnitude); // Create a Butterworth low-pass filter of order n and diameter d0 in the frequency domain cv::Mat lpf = BLPF(100, 2, wy, wx, cx, cy); cv::Mat bsf = BBSF(2, wy, wx, cx, cy); cv::Mat nf = BNF(2, wy, wx, cx, cy); // Multiply and shift back cv::mulSpectrums(nf, img_dft, img_dft, cv::DFT_ROWS); dftshift(img_dft); //Display high pass filter cv::Mat realImg[2]; cv::split(nf,realImg); cv::Mat realNF = realImg[0]; cv::normalize(realNF, realNF, 0.0, 1.0, CV_MINMAX); // namedWindow("", cv::WINDOW_NORMAL); cv::imwrite("NF.png", realNF); //----- Compute IDFT of HPF filtered image //you can do this //cv::idft(img_dft, img_dft); //the result is a 2 channel image //Mat output; // therefore you split it and get the real one //split(img_dft, imgs); //normalize(imgs[0], output, 0, 1, CV_MINMAX); //or you can do like this, then you dont need to split cv::Mat_<float> output; cv::dft(img_dft, output, cv::DFT_INVERSE| cv::DFT_REAL_OUTPUT); cv::Mat_<float> croppedOutput(output,cv::Rect(0,0,wxOrig,wyOrig)); cv::normalize(output, output, 0, 1, CV_MINMAX); cv::normalize(img, img, 0.0, 1.0, CV_MINMAX); // namedWindow("", cv::WINDOW_NORMAL); // cv::imshow("Input", img); cv::imwrite("out.png", croppedOutput * 255); // namedWindow("", cv::WINDOW_NORMAL); // cv::imshow("High-pass filtered input", croppedOutput); cv::waitKey(); return 0; return 0; }
void jointColorDepthFillOcclusion_(const Mat& src, const Mat& guide, Mat& dest, const Size ksize, T threshold) { if(dest.empty())dest.create(src.size(),src.type()); Mat sim,gim; const int radiusw = ksize.width/2; const int radiush = ksize.height/2;; copyMakeBorder(src, sim, radiush, radiush, radiusw, radiusw,cv::BORDER_DEFAULT); copyMakeBorder(guide, gim, radiush, radiush, radiusw, radiusw,cv::BORDER_DEFAULT); vector<int> _space_ofs_before(ksize.area()); int* space_ofs_before = &_space_ofs_before[0]; int maxk=0; for(int i = -radiush; i <= radiush; i++ ) { for(int j = -radiusw; j <= radiusw; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); if( r > radiusw ) continue; space_ofs_before[maxk++] = (int)(i*sim.cols + j); } } const int steps = sim.cols; const int step = dest.cols; T* sptr = sim.ptr<T>(radiush);sptr+=radiusw; uchar* jptr = gim.ptr<uchar>(radiush);jptr+=radiusw; T* dst = dest.ptr<T>(0); T th2 = threshold*threshold; for(int i = 0; i < src.rows; i++ ) { for(int j = 0; j < src.cols; j++ ) { const T val0j = jptr[j]; int minv=INT_MAX; T mind=0; if(sptr[j]==0) { for(int k = 0; k < maxk; k++ ) { if(sptr[j + space_ofs_before[k]]==0) continue; const T valj = jptr[j + space_ofs_before[k]]; int ab=(int)((valj-val0j)*(valj-val0j)); if(ab<minv) { minv=ab; mind= sptr[j + space_ofs_before[k]]; } } if(minv<th2) { dst[j]=mind; } } } sptr+=steps; jptr+=steps; dst+=step; } }
static bool convolve_dft(InputArray _image, InputArray _templ, OutputArray _result) { ConvolveBuf buf; CV_Assert(_image.type() == CV_32F); CV_Assert(_templ.type() == CV_32F); buf.create(_image.size(), _templ.size()); _result.create(buf.result_size, CV_32F); UMat image = _image.getUMat(); UMat templ = _templ.getUMat(); UMat result = _result.getUMat(); Size& block_size = buf.block_size; Size& dft_size = buf.dft_size; UMat& image_block = buf.image_block; UMat& templ_block = buf.templ_block; UMat& result_data = buf.result_data; UMat& image_spect = buf.image_spect; UMat& templ_spect = buf.templ_spect; UMat& result_spect = buf.result_spect; UMat templ_roi = templ; copyMakeBorder(templ_roi, templ_block, 0, templ_block.rows - templ_roi.rows, 0, templ_block.cols - templ_roi.cols, BORDER_ISOLATED); dft(templ_block, templ_spect, 0, templ.rows); // Process all blocks of the result matrix for (int y = 0; y < result.rows; y += block_size.height) { for (int x = 0; x < result.cols; x += block_size.width) { Size image_roi_size(std::min(x + dft_size.width, image.cols) - x, std::min(y + dft_size.height, image.rows) - y); Rect roi0(x, y, image_roi_size.width, image_roi_size.height); UMat image_roi(image, roi0); copyMakeBorder(image_roi, image_block, 0, image_block.rows - image_roi.rows, 0, image_block.cols - image_roi.cols, BORDER_ISOLATED); dft(image_block, image_spect, 0); mulSpectrums(image_spect, templ_spect, result_spect, 0, true); dft(result_spect, result_data, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT | cv::DFT_SCALE); Size result_roi_size(std::min(x + block_size.width, result.cols) - x, std::min(y + block_size.height, result.rows) - y); Rect roi1(x, y, result_roi_size.width, result_roi_size.height); Rect roi2(0, 0, result_roi_size.width, result_roi_size.height); UMat result_roi(result, roi1); UMat result_block(result_data, roi2); result_block.copyTo(result_roi); } } return true; }
/*---------------------------- * 功能 : 基于 BM 算法计算视差 *---------------------------- * 函数 : StereoMatch::bmMatch * 访问 : public * 返回 : 0 - 失败,1 - 成功 * * 参数 : frameLeft [in] 左摄像机帧图 * 参数 : frameRight [in] 右摄像机帧图 * 参数 : disparity [out] 视差图 * 参数 : imageLeft [out] 处理后的左视图,用于显示 * 参数 : imageRight [out] 处理后的右视图,用于显示 */ int StereoMatch::bmMatch(cv::Mat& frameLeft, cv::Mat& frameRight, cv::Mat& disparity, cv::Mat& imageLeft, cv::Mat& imageRight) { // 输入检查 if (frameLeft.empty() || frameRight.empty()) { disparity = cv::Scalar(0); return 0; } if (m_frameWidth == 0 || m_frameHeight == 0) { if (init(frameLeft.cols, frameLeft.rows, "calib_paras.xml"/*待改为由本地设置文件确定*/) == 0) //执行类初始化 { return 0; } } // 转换为灰度图 cv::Mat img1proc, img2proc; cvtColor(frameLeft, img1proc, CV_BGR2GRAY); cvtColor(frameRight, img2proc, CV_BGR2GRAY); // 校正图像,使左右视图行对齐 cv::Mat img1remap, img2remap; if (m_Calib_Data_Loaded) { remap(img1proc, img1remap, m_Calib_Mat_Remap_X_L, m_Calib_Mat_Remap_Y_L, cv::INTER_LINEAR); // 对用于视差计算的画面进行校正 remap(img2proc, img2remap, m_Calib_Mat_Remap_X_R, m_Calib_Mat_Remap_Y_R, cv::INTER_LINEAR); } else { img1remap = img1proc; img2remap = img2proc; } // 对左右视图的左边进行边界延拓,以获取与原始视图相同大小的有效视差区域 cv::Mat img1border, img2border; if (m_numberOfDisparies != m_BM.state->numberOfDisparities) m_numberOfDisparies = m_BM.state->numberOfDisparities; copyMakeBorder(img1remap, img1border, 0, 0, m_BM.state->numberOfDisparities, 0, IPL_BORDER_REPLICATE); copyMakeBorder(img2remap, img2border, 0, 0, m_BM.state->numberOfDisparities, 0, IPL_BORDER_REPLICATE); // 计算视差 cv::Mat dispBorder; m_BM(img1border, img2border, dispBorder); // 截取与原始画面对应的视差区域(舍去加宽的部分) cv::Mat disp; disp = dispBorder.colRange(m_BM.state->numberOfDisparities, img1border.cols); disp.copyTo(disparity, m_Calib_Mat_Mask_Roi); // 输出处理后的图像 if (m_Calib_Data_Loaded) remap(frameLeft, imageLeft, m_Calib_Mat_Remap_X_L, m_Calib_Mat_Remap_Y_L, cv::INTER_LINEAR); else frameLeft.copyTo(imageLeft); rectangle(imageLeft, m_Calib_Roi_L, CV_RGB(0,0,255), 3); if (m_Calib_Data_Loaded) remap(frameRight, imageRight, m_Calib_Mat_Remap_X_R, m_Calib_Mat_Remap_Y_R, cv::INTER_LINEAR); else frameRight.copyTo(imageRight); rectangle(imageRight, m_Calib_Roi_R, CV_RGB(0,0,255), 3); return 1; }
void crossCorr( const Mat& img, const Mat& _templ, Mat& corr, Size corrsize, int ctype, Point anchor, double delta, int borderType ) { const double blockScale = 4.5; const int minBlockSize = 256; std::vector<uchar> buf; Mat templ = _templ; int depth = img.depth(), cn = img.channels(); int tdepth = templ.depth(), tcn = templ.channels(); int cdepth = CV_MAT_DEPTH(ctype), ccn = CV_MAT_CN(ctype); CV_Assert( img.dims <= 2 && templ.dims <= 2 && corr.dims <= 2 ); if( depth != tdepth && tdepth != std::max(CV_32F, depth) ) { _templ.convertTo(templ, std::max(CV_32F, depth)); tdepth = templ.depth(); } CV_Assert( depth == tdepth || tdepth == CV_32F); CV_Assert( corrsize.height <= img.rows + templ.rows - 1 && corrsize.width <= img.cols + templ.cols - 1 ); CV_Assert( ccn == 1 || delta == 0 ); corr.create(corrsize, ctype); int maxDepth = depth > CV_8S ? CV_64F : std::max(std::max(CV_32F, tdepth), cdepth); Size blocksize, dftsize; blocksize.width = cvRound(templ.cols*blockScale); blocksize.width = std::max( blocksize.width, minBlockSize - templ.cols + 1 ); blocksize.width = std::min( blocksize.width, corr.cols ); blocksize.height = cvRound(templ.rows*blockScale); blocksize.height = std::max( blocksize.height, minBlockSize - templ.rows + 1 ); blocksize.height = std::min( blocksize.height, corr.rows ); dftsize.width = std::max(getOptimalDFTSize(blocksize.width + templ.cols - 1), 2); dftsize.height = getOptimalDFTSize(blocksize.height + templ.rows - 1); if( dftsize.width <= 0 || dftsize.height <= 0 ) CV_Error( CV_StsOutOfRange, "the input arrays are too big" ); // recompute block size blocksize.width = dftsize.width - templ.cols + 1; blocksize.width = MIN( blocksize.width, corr.cols ); blocksize.height = dftsize.height - templ.rows + 1; blocksize.height = MIN( blocksize.height, corr.rows ); Mat dftTempl( dftsize.height*tcn, dftsize.width, maxDepth ); Mat dftImg( dftsize, maxDepth ); int i, k, bufSize = 0; if( tcn > 1 && tdepth != maxDepth ) bufSize = templ.cols*templ.rows*CV_ELEM_SIZE(tdepth); if( cn > 1 && depth != maxDepth ) bufSize = std::max( bufSize, (blocksize.width + templ.cols - 1)* (blocksize.height + templ.rows - 1)*CV_ELEM_SIZE(depth)); if( (ccn > 1 || cn > 1) && cdepth != maxDepth ) bufSize = std::max( bufSize, blocksize.width*blocksize.height*CV_ELEM_SIZE(cdepth)); buf.resize(bufSize); // compute DFT of each template plane for( k = 0; k < tcn; k++ ) { int yofs = k*dftsize.height; Mat src = templ; Mat dst(dftTempl, Rect(0, yofs, dftsize.width, dftsize.height)); Mat dst1(dftTempl, Rect(0, yofs, templ.cols, templ.rows)); if( tcn > 1 ) { src = tdepth == maxDepth ? dst1 : Mat(templ.size(), tdepth, &buf[0]); int pairs[] = {k, 0}; mixChannels(&templ, 1, &src, 1, pairs, 1); } if( dst1.data != src.data ) src.convertTo(dst1, dst1.depth()); if( dst.cols > templ.cols ) { Mat part(dst, Range(0, templ.rows), Range(templ.cols, dst.cols)); part = Scalar::all(0); } dft(dst, dst, 0, templ.rows); } int tileCountX = (corr.cols + blocksize.width - 1)/blocksize.width; int tileCountY = (corr.rows + blocksize.height - 1)/blocksize.height; int tileCount = tileCountX * tileCountY; Size wholeSize = img.size(); Point roiofs(0,0); Mat img0 = img; if( !(borderType & BORDER_ISOLATED) ) { img.locateROI(wholeSize, roiofs); img0.adjustROI(roiofs.y, wholeSize.height-img.rows-roiofs.y, roiofs.x, wholeSize.width-img.cols-roiofs.x); } borderType |= BORDER_ISOLATED; // calculate correlation by blocks for( i = 0; i < tileCount; i++ ) { int x = (i%tileCountX)*blocksize.width; int y = (i/tileCountX)*blocksize.height; Size bsz(std::min(blocksize.width, corr.cols - x), std::min(blocksize.height, corr.rows - y)); Size dsz(bsz.width + templ.cols - 1, bsz.height + templ.rows - 1); int x0 = x - anchor.x + roiofs.x, y0 = y - anchor.y + roiofs.y; int x1 = std::max(0, x0), y1 = std::max(0, y0); int x2 = std::min(img0.cols, x0 + dsz.width); int y2 = std::min(img0.rows, y0 + dsz.height); Mat src0(img0, Range(y1, y2), Range(x1, x2)); Mat dst(dftImg, Rect(0, 0, dsz.width, dsz.height)); Mat dst1(dftImg, Rect(x1-x0, y1-y0, x2-x1, y2-y1)); Mat cdst(corr, Rect(x, y, bsz.width, bsz.height)); for( k = 0; k < cn; k++ ) { Mat src = src0; dftImg = Scalar::all(0); if( cn > 1 ) { src = depth == maxDepth ? dst1 : Mat(y2-y1, x2-x1, depth, &buf[0]); int pairs[] = {k, 0}; mixChannels(&src0, 1, &src, 1, pairs, 1); } if( dst1.data != src.data ) src.convertTo(dst1, dst1.depth()); if( x2 - x1 < dsz.width || y2 - y1 < dsz.height ) copyMakeBorder(dst1, dst, y1-y0, dst.rows-dst1.rows-(y1-y0), x1-x0, dst.cols-dst1.cols-(x1-x0), borderType); dft( dftImg, dftImg, 0, dsz.height ); Mat dftTempl1(dftTempl, Rect(0, tcn > 1 ? k*dftsize.height : 0, dftsize.width, dftsize.height)); mulSpectrums(dftImg, dftTempl1, dftImg, 0, true); dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height ); src = dftImg(Rect(0, 0, bsz.width, bsz.height)); if( ccn > 1 ) { if( cdepth != maxDepth ) { Mat plane(bsz, cdepth, &buf[0]); src.convertTo(plane, cdepth, 1, delta); src = plane; } int pairs[] = {0, k}; mixChannels(&src, 1, &cdst, 1, pairs, 1); } else { if( k == 0 ) src.convertTo(cdst, cdepth, 1, delta); else { if( maxDepth != cdepth ) { Mat plane(bsz, cdepth, &buf[0]); src.convertTo(plane, cdepth); src = plane; } add(src, cdst, cdst); } } } } }
Point2d phaseCorrelate(InputArray _src1, InputArray _src2, InputArray _window, double* response) { Mat src1 = _src1.getMat(); Mat src2 = _src2.getMat(); Mat window = _window.getMat(); CV_Assert( src1.type() == src2.type()); CV_Assert( src1.type() == CV_32FC1 || src1.type() == CV_64FC1 ); CV_Assert( src1.size == src2.size); if(!window.empty()) { CV_Assert( src1.type() == window.type()); CV_Assert( src1.size == window.size); } int M = getOptimalDFTSize(src1.rows); int N = getOptimalDFTSize(src1.cols); Mat padded1, padded2, paddedWin; if(M != src1.rows || N != src1.cols) { copyMakeBorder(src1, padded1, 0, M - src1.rows, 0, N - src1.cols, BORDER_CONSTANT, Scalar::all(0)); copyMakeBorder(src2, padded2, 0, M - src2.rows, 0, N - src2.cols, BORDER_CONSTANT, Scalar::all(0)); if(!window.empty()) { copyMakeBorder(window, paddedWin, 0, M - window.rows, 0, N - window.cols, BORDER_CONSTANT, Scalar::all(0)); } } else { padded1 = src1; padded2 = src2; paddedWin = window; } // perform window multiplication if available if(!paddedWin.empty()) { // apply window to both images before proceeding... multiply(paddedWin, padded1, padded1); multiply(paddedWin, padded2, padded2); } // execute phase correlation equation // Reference: http://en.wikipedia.org/wiki/Phase_correlation cv::Mat FFT1, FFT2; dft(padded1, FFT1, DFT_COMPLEX_OUTPUT); dft(padded2, FFT2, DFT_COMPLEX_OUTPUT); // // high-pass filter // cv::Mat hpFilter = 1-paddedWin; // phasecorrelation::fftShift(hpFilter); // for(int i=0; i<paddedWin.rows; i++){ // for(int j=0; j<paddedWin.cols; j++){ // FFT1.at<cv::Vec2f>(i,j) *= hpFilter.at<float>(i,j); // FFT2.at<cv::Vec2f>(i,j) *= hpFilter.at<float>(i,j); // } // } cv::Mat P; cv::mulSpectrums(FFT1, FFT2, P, DFT_COMPLEX_OUTPUT, true); cv::Mat Pm(P.size(), CV_32F); // NOTE: memleak in magSpectrums when using it with complex output! //phasecorrelation::magSpectrums(P, Pm); for(int i=0; i<P.rows; i++){ for(int j=0; j<P.cols; j++){ cv::Vec2f e = P.at<cv::Vec2f>(i, j); Pm.at<float>(i, j) = cv::sqrt(e[0]*e[0] + e[1]*e[1]); } } //phasecorrelation::divSpectrums(P, Pm, C, 0, false); // FF* / |FF*| (phase correlation equation completed here...) for(int i=0; i<P.rows; i++){ for(int j=0; j<P.cols; j++){ P.at<cv::Vec2f>(i, j) /= (Pm.at<float>(i, j) + DBL_EPSILON); } } cv::Mat C(P.size(), CV_32F); cv::dft(P, C, cv::DFT_INVERSE + cv::DFT_REAL_OUTPUT); phasecorrelation::fftShift(C); // shift the energy to the center of the frame. //cvtools::writeMat(C, "C.mat", "C"); // locate the highest peak Point peakLoc; minMaxLoc(C, NULL, NULL, NULL, &peakLoc); // get the phase shift with sub-pixel accuracy, 5x5 window seems about right here... Point2d t = phasecorrelation::weightedCentroid(C, peakLoc, Size(3, 3), response); // max response is M*N (not exactly, might be slightly larger due to rounding errors) if(response) *response /= M*N; // adjust shift relative to image center... Point2d center((double)padded1.cols / 2.0, (double)padded1.rows / 2.0); return (center - t); }
void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) { #if ENABLE_LOG int64 t = getTickCount(); #endif UMat img = _img.getUMat(); CV_Assert(img.type() == CV_16SC3 || img.type() == CV_8UC3); CV_Assert(mask.type() == CV_8U); // Keep source image in memory with small border int gap = 3 * (1 << num_bands_); Point tl_new(std::max(dst_roi_.x, tl.x - gap), std::max(dst_roi_.y, tl.y - gap)); Point br_new(std::min(dst_roi_.br().x, tl.x + img.cols + gap), std::min(dst_roi_.br().y, tl.y + img.rows + gap)); // Ensure coordinates of top-left, bottom-right corners are divided by (1 << num_bands_). // After that scale between layers is exactly 2. // // We do it to avoid interpolation problems when keeping sub-images only. There is no such problem when // image is bordered to have size equal to the final image size, but this is too memory hungry approach. tl_new.x = dst_roi_.x + (((tl_new.x - dst_roi_.x) >> num_bands_) << num_bands_); tl_new.y = dst_roi_.y + (((tl_new.y - dst_roi_.y) >> num_bands_) << num_bands_); int width = br_new.x - tl_new.x; int height = br_new.y - tl_new.y; width += ((1 << num_bands_) - width % (1 << num_bands_)) % (1 << num_bands_); height += ((1 << num_bands_) - height % (1 << num_bands_)) % (1 << num_bands_); br_new.x = tl_new.x + width; br_new.y = tl_new.y + height; int dy = std::max(br_new.y - dst_roi_.br().y, 0); int dx = std::max(br_new.x - dst_roi_.br().x, 0); tl_new.x -= dx; br_new.x -= dx; tl_new.y -= dy; br_new.y -= dy; int top = tl.y - tl_new.y; int left = tl.x - tl_new.x; int bottom = br_new.y - tl.y - img.rows; int right = br_new.x - tl.x - img.cols; // Create the source image Laplacian pyramid UMat img_with_border; copyMakeBorder(_img, img_with_border, top, bottom, left, right, BORDER_REFLECT); LOGLN(" Add border to the source image, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); #if ENABLE_LOG t = getTickCount(); #endif std::vector<UMat> src_pyr_laplace; if (can_use_gpu_ && img_with_border.depth() == CV_16S) createLaplacePyrGpu(img_with_border, num_bands_, src_pyr_laplace); else createLaplacePyr(img_with_border, num_bands_, src_pyr_laplace); LOGLN(" Create the source image Laplacian pyramid, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); #if ENABLE_LOG t = getTickCount(); #endif // Create the weight map Gaussian pyramid UMat weight_map; std::vector<UMat> weight_pyr_gauss(num_bands_ + 1); if(weight_type_ == CV_32F) { mask.getUMat().convertTo(weight_map, CV_32F, 1./255.); } else // weight_type_ == CV_16S { mask.getUMat().convertTo(weight_map, CV_16S); UMat add_mask; compare(mask, 0, add_mask, CMP_NE); add(weight_map, Scalar::all(1), weight_map, add_mask); } copyMakeBorder(weight_map, weight_pyr_gauss[0], top, bottom, left, right, BORDER_CONSTANT); for (int i = 0; i < num_bands_; ++i) pyrDown(weight_pyr_gauss[i], weight_pyr_gauss[i + 1]); LOGLN(" Create the weight map Gaussian pyramid, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); #if ENABLE_LOG t = getTickCount(); #endif int y_tl = tl_new.y - dst_roi_.y; int y_br = br_new.y - dst_roi_.y; int x_tl = tl_new.x - dst_roi_.x; int x_br = br_new.x - dst_roi_.x; // Add weighted layer of the source image to the final Laplacian pyramid layer for (int i = 0; i <= num_bands_; ++i) { Rect rc(x_tl, y_tl, x_br - x_tl, y_br - y_tl); #ifdef HAVE_OPENCL if ( !cv::ocl::useOpenCL() || !ocl_MultiBandBlender_feed(src_pyr_laplace[i], weight_pyr_gauss[i], dst_pyr_laplace_[i](rc), dst_band_weights_[i](rc)) ) #endif { Mat _src_pyr_laplace = src_pyr_laplace[i].getMat(ACCESS_READ); Mat _dst_pyr_laplace = dst_pyr_laplace_[i](rc).getMat(ACCESS_RW); Mat _weight_pyr_gauss = weight_pyr_gauss[i].getMat(ACCESS_READ); Mat _dst_band_weights = dst_band_weights_[i](rc).getMat(ACCESS_RW); if(weight_type_ == CV_32F) { for (int y = 0; y < rc.height; ++y) { const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y); Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y); const float* weight_row = _weight_pyr_gauss.ptr<float>(y); float* dst_weight_row = _dst_band_weights.ptr<float>(y); for (int x = 0; x < rc.width; ++x) { dst_row[x].x += static_cast<short>(src_row[x].x * weight_row[x]); dst_row[x].y += static_cast<short>(src_row[x].y * weight_row[x]); dst_row[x].z += static_cast<short>(src_row[x].z * weight_row[x]); dst_weight_row[x] += weight_row[x]; } } } else // weight_type_ == CV_16S { for (int y = 0; y < y_br - y_tl; ++y) { const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y); Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y); const short* weight_row = _weight_pyr_gauss.ptr<short>(y); short* dst_weight_row = _dst_band_weights.ptr<short>(y); for (int x = 0; x < x_br - x_tl; ++x) { dst_row[x].x += short((src_row[x].x * weight_row[x]) >> 8); dst_row[x].y += short((src_row[x].y * weight_row[x]) >> 8); dst_row[x].z += short((src_row[x].z * weight_row[x]) >> 8); dst_weight_row[x] += weight_row[x]; } } } } #ifdef HAVE_OPENCL else {
// ============================================================================ //for drawing examples see // http://opencvexamples.blogspot.com/2013/10/basic-drawing-examples.html void VideoReader::nextFrame() { // if (!playingOptions.playing) { return; } Mat inputFrame; if (!capture.read(inputFrame)) { emit finished() ; return; } int gfw = inputFrame.cols; int gfh = inputFrame.rows; float scaleFactor =1; if ( (inputFrame.cols>playingOptions.guiFrameWidth) || (inputFrame.rows>playingOptions.guiFrameHeight) ) { if (playingOptions.guiFrameWidth > playingOptions.guiFrameHeight) { gfw = playingOptions.guiFrameWidth ; scaleFactor = (playingOptions.guiFrameWidth*1.0)/inputFrame.cols ; gfh = (int)round(inputFrame.rows*scaleFactor) ; } else { gfh = playingOptions.guiFrameHeight ; scaleFactor = (playingOptions.guiFrameHeight*1.0)/inputFrame.rows ; gfw = (int)round(inputFrame.cols*scaleFactor) ; } } // c5d(c5, QString("Calculated scale from %1x%2 to %3x%4 (%5)") // .arg(inputFrame.cols).arg(inputFrame.rows) // .arg(playingOptions.guiFrameWidth).arg(playingOptions.guiFrameHeight) // .arg(scaleFactor) ) ; resize(inputFrame, frame, Size(gfw, gfh) ); drawCornerCircles(); switch (playingOptions.crosshairType) { case 0 : drawCrosshairType1(scaleFactor); break; case 1 : drawCrosshairType2(scaleFactor); break; case 2 : drawCrosshairType3(scaleFactor); break; } // drawSelectorRectangle(scaleFactor); drawFilename(scaleFactor); Mat fullFrame = Mat::zeros(playingOptions.guiFrameWidth, playingOptions.guiFrameHeight, CV_8UC3); const int topShift = (playingOptions.guiFrameHeight-frame.rows) /2 ; const int lowShift = playingOptions.guiFrameHeight - topShift - frame.rows; // copyMakeBorder(frame, fullFrame, topShift, lowShift, 0,0,BORDER_REPLICATE ); copyMakeBorder(frame, fullFrame, topShift, lowShift, 0,0,BORDER_CONSTANT, Scalar( 128, 128, 0 ) ); frame = fullFrame; if (frame.channels()== 3){ cv::cvtColor(frame, RGBframe, CV_BGR2RGB); img = QImage((const unsigned char*)(RGBframe.data), RGBframe.cols,RGBframe.rows, RGBframe.step, QImage::Format_RGB888); } else { img = QImage((const unsigned char*)(frame.data), frame.cols,frame.rows,QImage::Format_Indexed8); } emit processedImage(img); }
static Mat inverseAndWiener(Mat& s, Mat& p, double snr, bool inverse) { const bool wiener = !inverse; // Pad input image to avoid ringing artifacts along image borders. int bH = p.cols; int bV = p.rows; Mat sBorder; copyMakeBorder(s, sBorder, bV, bV, bH, bH, BORDER_REPLICATE); // Allocate some memory like it is going out of style. Mat pBigShifted = Mat::zeros(sBorder.size(), CV_32F); Mat P = Mat::zeros(sBorder.size(), CV_32F); Mat S = Mat::zeros(sBorder.size(), CV_32F); Mat OApprox = Mat::zeros(sBorder.size(), CV_32F); Mat oApprox = Mat::zeros(sBorder.size(), CV_32F); // Shift kernel. const int pHalf = p.rows / 2; circShiftXXX(p, pBigShifted, -pHalf, -pHalf); // Transform shifted kernel and degrated input image into frequency domain. // Note: DFT_COMPLEX_OUTPUT means that we want the complex result to be stored // in a two-channel matrix as opposed to the default compressed output. dft(pBigShifted, P, DFT_COMPLEX_OUTPUT); dft(sBorder, S, DFT_COMPLEX_OUTPUT); if (inverse) { const double epsilon = 0.05f; // Remove frequencies whose magnitude is below epsilon * max(freqKernel magnitude). double maxMagnitude; minMaxLoc(abs(P), 0, &maxMagnitude); const double threshold = maxMagnitude * epsilon; for (int ri = 0; ri < P.rows; ri++) { for (int ci = 0; ci < P.cols; ci++) { if (norm(P.at<Vec2f>(ri, ci)) < threshold) { P.at<Vec2f>(ri, ci) = threshold; } } } } // OpenCV only provides a multiplication operation for complex matrices, so we need // to calculate the inverse (1/H) of our filter spectrum first. Since it is complex // we need to compute 1/H = H*/(HH*) = H*/(Re(H)^2+Im(H)^2), where H* -> complex conjugate of H. // Multiply spectrum of the degrated image with the complex conjugate of the frequency spectrum // of the filter. const bool conjFreqKernel = true; mulSpectrums(S, P, OApprox, DFT_COMPLEX_OUTPUT, conjFreqKernel); // I * H* // Split kernel spectrum into real and imaginary parts. Mat PChannels[] = {Mat::zeros(sBorder.size(), CV_32F), Mat::zeros(sBorder.size(), CV_32F)}; split(P, PChannels); // 0:real, 1:imaginary // Calculate squared magnitude (Re(H)^2 + Im(H)^2) of filter spectrum. Mat freqKernelSqMagnitude = Mat::zeros(sBorder.rows, sBorder.cols, CV_32F); magnitude(PChannels[0], PChannels[1], freqKernelSqMagnitude); // freqKernelSqMagnitude = magnitude pow(PChannels[0], 2, freqKernelSqMagnitude); // freqKernelSqMagnitude = magnitude^2 = Re(H)^2 + Im(H)^2 if (wiener) { // Add 1 / SNR^2 to the squared filter kernel magnitude. freqKernelSqMagnitude += 1 / pow(snr, 2.0); } // Split frequency spectrum of degradedPadded image into real and imaginary parts. Mat OApproxChannels[] = {Mat::zeros(sBorder.size(), CV_32FC1), Mat::zeros(sBorder.size(), CV_32F)}; split(OApprox, OApproxChannels); // Divide each plane by the squared magnitude of the kernel frequency spectrum. // What we have done up to this point: (I * H*) / (Re(H)^2 + Im(H)^2) = I/H divide(OApproxChannels[0], freqKernelSqMagnitude, OApproxChannels[0]); // Re(I) / (Re(H)^2 + Im(H)^2) divide(OApproxChannels[1], freqKernelSqMagnitude, OApproxChannels[1]); // Im(I) / (Re(H)^2 + Im(H)^2) // Merge real and imaginary parts of the image frequency spectrum. merge(OApproxChannels, 2, OApprox); // Inverse DFT. // Note: DFT_REAL_OUTPUT means that we want the output to be a one-channel matrix again. dft(OApprox, oApprox, DFT_INVERSE | DFT_SCALE | DFT_REAL_OUTPUT); // Crop output image to original size. oApprox = oApprox(Rect(bH, bV, oApprox.cols - (bH * 2), oApprox.rows - (bV * 2))); return oApprox; }
void MultiBandBlender::feed(const Mat &img, const Mat &mask, Point tl) { CV_Assert(img.type() == CV_16SC3 || img.type() == CV_8UC3); CV_Assert(mask.type() == CV_8U); // Keep source image in memory with small border int gap = 3 * (1 << num_bands_); Point tl_new(std::max(dst_roi_.x, tl.x - gap), std::max(dst_roi_.y, tl.y - gap)); Point br_new(std::min(dst_roi_.br().x, tl.x + img.cols + gap), std::min(dst_roi_.br().y, tl.y + img.rows + gap)); // Ensure coordinates of top-left, bottom-right corners are divided by (1 << num_bands_). // After that scale between layers is exactly 2. // // We do it to avoid interpolation problems when keeping sub-images only. There is no such problem when // image is bordered to have size equal to the final image size, but this is too memory hungry approach. tl_new.x = dst_roi_.x + (((tl_new.x - dst_roi_.x) >> num_bands_) << num_bands_); tl_new.y = dst_roi_.y + (((tl_new.y - dst_roi_.y) >> num_bands_) << num_bands_); int width = br_new.x - tl_new.x; int height = br_new.y - tl_new.y; width += ((1 << num_bands_) - width % (1 << num_bands_)) % (1 << num_bands_); height += ((1 << num_bands_) - height % (1 << num_bands_)) % (1 << num_bands_); br_new.x = tl_new.x + width; br_new.y = tl_new.y + height; int dy = std::max(br_new.y - dst_roi_.br().y, 0); int dx = std::max(br_new.x - dst_roi_.br().x, 0); tl_new.x -= dx; br_new.x -= dx; tl_new.y -= dy; br_new.y -= dy; int top = tl.y - tl_new.y; int left = tl.x - tl_new.x; int bottom = br_new.y - tl.y - img.rows; int right = br_new.x - tl.x - img.cols; // Create the source image Laplacian pyramid Mat img_with_border; copyMakeBorder(img, img_with_border, top, bottom, left, right, BORDER_REFLECT); std::vector<Mat> src_pyr_laplace; if (can_use_gpu_ && img_with_border.depth() == CV_16S) createLaplacePyrGpu(img_with_border, num_bands_, src_pyr_laplace); else createLaplacePyr(img_with_border, num_bands_, src_pyr_laplace); // Create the weight map Gaussian pyramid Mat weight_map; std::vector<Mat> weight_pyr_gauss(num_bands_ + 1); if(weight_type_ == CV_32F) { mask.convertTo(weight_map, CV_32F, 1./255.); } else// weight_type_ == CV_16S { mask.convertTo(weight_map, CV_16S); add(weight_map, 1, weight_map, mask != 0); } copyMakeBorder(weight_map, weight_pyr_gauss[0], top, bottom, left, right, BORDER_CONSTANT); for (int i = 0; i < num_bands_; ++i) pyrDown(weight_pyr_gauss[i], weight_pyr_gauss[i + 1]); int y_tl = tl_new.y - dst_roi_.y; int y_br = br_new.y - dst_roi_.y; int x_tl = tl_new.x - dst_roi_.x; int x_br = br_new.x - dst_roi_.x; // Add weighted layer of the source image to the final Laplacian pyramid layer if(weight_type_ == CV_32F) { for (int i = 0; i <= num_bands_; ++i) { for (int y = y_tl; y < y_br; ++y) { int y_ = y - y_tl; const Point3_<short>* src_row = src_pyr_laplace[i].ptr<Point3_<short> >(y_); Point3_<short>* dst_row = dst_pyr_laplace_[i].ptr<Point3_<short> >(y); const float* weight_row = weight_pyr_gauss[i].ptr<float>(y_); float* dst_weight_row = dst_band_weights_[i].ptr<float>(y); for (int x = x_tl; x < x_br; ++x) { int x_ = x - x_tl; dst_row[x].x += static_cast<short>(src_row[x_].x * weight_row[x_]); dst_row[x].y += static_cast<short>(src_row[x_].y * weight_row[x_]); dst_row[x].z += static_cast<short>(src_row[x_].z * weight_row[x_]); dst_weight_row[x] += weight_row[x_]; } } x_tl /= 2; y_tl /= 2; x_br /= 2; y_br /= 2; } } else// weight_type_ == CV_16S { for (int i = 0; i <= num_bands_; ++i) { for (int y = y_tl; y < y_br; ++y) { int y_ = y - y_tl; const Point3_<short>* src_row = src_pyr_laplace[i].ptr<Point3_<short> >(y_); Point3_<short>* dst_row = dst_pyr_laplace_[i].ptr<Point3_<short> >(y); const short* weight_row = weight_pyr_gauss[i].ptr<short>(y_); short* dst_weight_row = dst_band_weights_[i].ptr<short>(y); for (int x = x_tl; x < x_br; ++x) { int x_ = x - x_tl; dst_row[x].x += short((src_row[x_].x * weight_row[x_]) >> 8); dst_row[x].y += short((src_row[x_].y * weight_row[x_]) >> 8); dst_row[x].z += short((src_row[x_].z * weight_row[x_]) >> 8); dst_weight_row[x] += weight_row[x_]; } } x_tl /= 2; y_tl /= 2; x_br /= 2; y_br /= 2; } } }