题目:图片去毛刺

优质解答:

#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
bool SmoothEdgeSingleChannel( Mat mInput,Mat &mOutput, double amount, double radius, uchar Threshold) ;
bool SmoothEdge( Mat mInput_Bgr,Mat &mOutput_Bgr, double amount, double radius, uchar Threshold) 
{if(mInput_Bgr.empty()){return 0;}if(radius<1)radius=1;Mat mInput,mOutput;Mat mChannel[3];split(mInput_Bgr,mChannel);for (int i = 0; i < 3; i++){mInput= mChannel[i];SmoothEdgeSingleChannel(mInput,mOutput,amount, radius,Threshold); mOutput.copyTo(mChannel[i]);}merge(mChannel,3,mOutput_Bgr);return true;
}
bool SmoothEdgeSingleChannel( Mat mInput,Mat &mOutput, double amount, double radius, uchar Threshold) 
{if(mInput.empty()){return 0;}if(radius<1)radius=1;Mat mGSmooth,mDiff,mAbsDiff;mOutput = Mat(mInput.size(),mInput.type());GaussianBlur(mInput,mGSmooth,Size(0,0),radius); //imshow("mGSmooth",mGSmooth);subtract(mGSmooth,mInput,mDiff);//imshow("mDiff",mDiff);mDiff*=amount;threshold(abs(2* mDiff),mAbsDiff,Threshold,255,THRESH_BINARY_INV);mDiff.setTo(Scalar(0),mAbsDiff);//imshow("mDiff Multiplied",mDiff);add(mInput,mDiff,mOutput);return true;
}
//Credits: http://stackoverflow.com/questions/34527349/non-connecting-morphological-filter/34535023#34535023
bool SmoothContours(vector<vector<Point>> contours_Src,vector<vector<Point>> &contours_Smooth,int Radius,double Sigma )
{if(contours_Src.size()==0)return false;int FilterSize = 2 * Radius + 1;for (int id = 0; id < contours_Src.size(); id++){size_t len = contours_Src[id].size() + 2 * Radius;size_t idx = (contours_Src[id].size() - Radius);vector<float> x, y;vector<float> xFilt, yFilt;vector<Point> contours_Smooth_Curr;for (size_t i = 0; i < len; i++){x.push_back(contours_Src[id][(idx + i) % contours_Src[id].size()].x);y.push_back(contours_Src[id][(idx + i) % contours_Src[id].size()].y);}GaussianBlur(x, xFilt, Size(FilterSize, FilterSize), Sigma, Sigma);GaussianBlur(y, yFilt, Size(FilterSize, FilterSize), Sigma, Sigma);for (size_t i = Radius; i < contours_Src[id].size() + Radius; i++){contours_Smooth_Curr.push_back(Point(xFilt[i], yFilt[i]));}contours_Smooth.push_back(contours_Smooth_Curr);}return true;
}
int main(int argc, char* argv[])
{string FileName_S="e:/template/input.png";Mat mSource,mThres,mResult,mSmoothEdge;mSource= imread(FileName_S,0);RNG rng(12345);if(mSource.empty()){cout<<"[Error] Invalid Input Image!";return 0;}mSmoothEdge= mSource.clone();mSmoothEdge.setTo(0);threshold(mSource,mThres,125,255,THRESH_BINARY_INV);imshow("Source mThres",mThres);cvtColor(mSource,mResult,COLOR_GRAY2BGR);vector<vector<Point>> contours;vector<Vec4i> hierarchy;vector<vector<Point>> contours_Smoothed;int Radius=1;double Sigma=2.0;findContours( mThres.clone(), contours, hierarchy, RETR_TREE, CV_CHAIN_APPROX_SIMPLE );//Smoothing Contour Points using Gaussian Smooth!SmoothContours(contours,contours_Smoothed,Radius,Sigma);for( size_t i = 0; i< contours.size(); i++ ){/*Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );drawContours( mResult, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );*/if(hierarchy[i][2]<0)//These are inner most child contours{drawContours( mSmoothEdge, contours_Smoothed, i, Scalar(0), -1, 8, vector<Vec4i>(), 0, Point() );}if(hierarchy[i][3]<0)//These are outer most parent contours{drawContours( mSmoothEdge, contours_Smoothed, i, Scalar(255), -1, 8, vector<Vec4i>(), 0, Point() );}}//imshow("Source Image",mResult);imshow("1) Smooth Edge Points",mSmoothEdge);//Smoothing Edge using Modified Unsharp MaskingmSmoothEdge.setTo(0);SmoothEdgeSingleChannel(mThres,mSmoothEdge,2.5,1.0,254);imshow("2) Smooth Edges",mSmoothEdge);waitKey();
}

解析:

这个效果是不错的,但是废话太多了;精华部分值得体会。注意在做“边界获得”运算后,适当放大后加回了原始图像。

#include "stdafx.h"
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
bool SmoothEdgeSingleChannel( Mat mInput,Mat &mOutput, double amount, double radius, uchar Threshold) 
{if(mInput.empty()){return 0;}if(radius<1)radius=1;Mat mGSmooth,mDiff,mAbsDiff;mOutput = Mat(mInput.size(),mInput.type());GaussianBlur(mInput,mGSmooth,Size(0,0),radius); //imshow("mGSmooth",mGSmooth);subtract(mGSmooth,mInput,mDiff);//imshow("mDiff",mDiff);mDiff*=amount;threshold(abs(2* mDiff),mAbsDiff,Threshold,255,THRESH_BINARY_INV);mDiff.setTo(Scalar(0),mAbsDiff);//imshow("mDiff Multiplied",mDiff);add(mInput,mDiff,mOutput);return true;
}
int main(int argc, char* argv[])
{string FileName_S="e:/template/input.png";Mat src = imread(FileName_S,0);Mat dst;imshow("src",src);bitwise_not(src,src);SmoothEdgeSingleChannel(src,dst,2.5,1.0,254);imshow("dst",dst);waitKey();
} 
2、 Removing noise from Contour features in Real time

Hi,

In my project, I apply findcontours function to detect a rectangular object within a region of interest in the image. I am doing it in real time. Subsequently, I enclose the detected contour by a boundedrect which gives me its four vertices. However, the position of these vertices is not stable, it is changing very fast. Looks like the contour area is growing and shrinking, and have variations which causes the vertices' position to change. I have tried following solutions, but to no avail.

  1. Low pass filtering on the output of pixel positions.
  2. Median and Gaussian blur within the ROI.
  3. FastNlmeansDenoising: which is too slow for my application.
//medianBlur(img, img, 21);cvtColor (img, img, COLOR_BGR2GRAY);//fastNlMeansDenoising (img, img, 3, 7, 21);threshold(img, img, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);//medianBlur(img, img, 21);Mat dilateElement = getStructuringElement( MORPH_RECT,Size(11,11));//Mat erodeElement = getStructuringElement ( MORPH_RECT, Size(8,8) );dilate(img,img,dilateElement);//erode (img, img, erodeElement);floodFill (img, Point(0,0), Scalar(0));//  namedWindow("dilated",CV_WINDOW_NORMAL);//  imshow("dilated",img);//  cout << "Inside corrected corners p3" << endl;//GaussianBlur (img, img, Size(15,15), 0, 0);Canny (img, img, 0, 10, 5);dilate(img, img, Mat(), Point(-1,-1));//cout << "Inside corrected corners p3.5" << endl;findContours(img, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);// cout<<contours.size()<<endl;//  Mat tempimg(img.rows, img.cols, CV_8U, cv::Scalar(0));//  drawContours( tempimg, contours, -1, Scalar(255), 3, CV_AA );//  namedWindow("contours", CV_WINDOW_NORMAL);//  imshow("contours", tempimg);//  cout << "Inside corrected corners p4" << endl;

这个问题在AnswerOpenCV上也是讨论的很激烈,但是大多数还是从去噪音这个思路来说的 。

我认为在实时项目中(比如android),如果还是用静态图片的同样的处理方法来处理图片和寻找轮廓,肯定是会出现“颠簸”的情况。因此在考虑单幅图片的时候,还要同时考虑前面的/后面的图片;如果转换,也需要平滑处理。这些应该都是图像处理以外的东西了。