The basic implementation of global threshold processing for edge improvement is:
1. Calculate its boundary first, use Laplace or gradient transform to all.
2. Calculate the absolute value of the changed boundary image
3. Specify a threshold (generally as a percentage of the specified, such as I specify 90%, if there is a grayscale K, grayscale is less than K of the total number of pixels of 90%, then K is the grayscale we require)
4. Convert the threshold value of the computed image in 2 to a 2-value image
5. The original image is multiplied by the two-value image computed in 4.
6. Calculates the histogram in the image computed in 5 with a grayscale greater than 0.
7. Global partitioning of the histogram obtained in 6.
8. Proposed the global separation of gray, with the gray to the original image threshold segmentation, you can get results.
C # Algorithm implementation
Main function:
<summary>///Boundary Modified Adaptive threshold transform///</summary>///<param name= "image" > Input image </ param>///<param name= "percent" >% </param>///<returns></returns> PU
Blic static Mat Edgemodifyotsu (Mat image,double percent=0.99) {Mat _m = new Mat ();//Laplace transformed image
Mat _m1 = new Mat (); Mat _rmat = new Mat ()//The image/Laplace transform to return Cvinvoke.laplacian (image, _m, Emgu.CV.CvEnum.DepthType.Cv1
6s,3);
Take absolute value _m1 = abscv16s (_m);
Threshold Transform Double max = Percentgary (_m1, percent);
Cvinvoke.threshold (_M1, _M1, Max, 1, Emgu.CV.CvEnum.ThresholdType.Binary);
Convert to 8 bytes _m1 = cv16sto8u (_M1);
Multiplies with the original image cvinvoke.multiply (_m1, image, _M1, 1, Emgu.CV.CvEnum.DepthType.Cv8U);
Look for an adaptive threshold int _k = Otsuthreshold (_m1, 1) of the histogram with a gray scale greater than 0 after multiplication; CviNvoke.
Threshold (image, _rmat, _k, 255, Emgu.CV.CvEnum.ThresholdType.Binary);
return _rmat; }
Take the absolute value function:
<summary>///The gray value of 16-bit pixels///</summary>///<param name= "image" > Picture </p
aram>///<returns> converted pictures </returns> public static Mat abscv16s (Mat image) { Mat _m_ = new Mat (image.
Size, Emgu.CV.CvEnum.DepthType.Cv16S, 1); unsafe {int16* dataimage = (int16*) image.
Datapointer.topointer (); int16* data_m_ = (int16*) _m_.
Datapointer.topointer (); for (int row = 0; row < image. Height; row++) {//data = data + row * image.
Cols; for (int col = 0; col < image. Width;
col++) {Int16 _ii = *dataimage;
* data_m_ = Math.Abs (_ii);
dataimage++;
data_m_++;
}
}
} return _m_; }
To calculate a split function in percent:
<summary>
///calculate picture percent pixel gray value
///</summary>
///<param name= "image" > Input picture </param >
///<param name= "percent" > percent pixel </param>
///<returns> return grayscale value </returns>
public static double Percentgary (Mat image, double percent)
{
long[] _his = histogram (image, 0,16);
Long _count = 0;//indicates the pixel exists in K for
(int _index = 0; _index < Math.pow (2,16); _index++)//If all pixels are within K, the variance is set to 0
{
_count + = _his[_index];
if (double) _count/image. Total.toint64 () > percent)
{return
_index;
}
}
Return Math.pow (2);
Converts a 16-bit signed binary image to a 8-bit zero-digit binary image function:
<summary>
///converts 16 signed bit binary graphs to 8-bit
///</summary>
///<param name= "image" > Picture </param >
///<returns> return converted pictures </returns> public
static Mat cv16sto8u (Mat image)
{
Mat = New Mat (image. Size, Emgu.CV.CvEnum.DepthType.Cv8U, 1);
Unsafe
{
int16* dataimage = (int16*) image. Datapointer.topointer ();
byte* data_m_ = (byte*) _m_. Datapointer.topointer ();
for (int row = 0; row < image. Height; row++)
{
//data = data + row * image. Cols;
for (int col = 0; col < image. Width; col++)
{
*data_m_ = Convert.tobyte (Math.Abs (*dataimage));
dataimage++;
data_m_++
}
}} return _m_;
}
Look for an adaptive threshold function that multiplies the histogram of the image with a gray value greater than 0:
<summary>///Find the most adaptive thresholds for images larger than D-valued pixels///</summary>///<param name= "image" > Input
Pictures </param>///<param name= "D" ></param>///<returns> return the most appropriate threshold </returns>
public static int Otsuthreshold (Mat image, int d) {long[] his = histogram (image,8,d);
float _PK; Float _mk;//K-level additive gray mean value; float _mg = 0;//The entire picture's grayscale mean long _mn = 0;//Picture's number of pixels float[] _ks = New float[256];//storage class value maximum variance float _max;//maximum variance between classes list<int> _maxks = new list<int> ();//Storage Multiple k values that maximize variance between classes; for (int _index = 0; _index < his. Length;
_index++)//Calculate the total number of pixels in the histogram {_mn + = His[_index]; for (int i = 0; i < 256 i++)//Calculate picture average grayscale value {_mg + = (float) (I * (double) his[i]
/_mn); for (int k = 0; k < 256; k++)//Calculate the maximum square of the class value of the picture at different Kdifference {Long _count = 0;//represents the pixel in K for (int _index = 0; _index <= K; _index++
)//If all pixels are within K, the variance is set to 0 {_count + = His[_index];
} if (_count = = _mn) {_ks[k] = 0;
Continue
else if (_count = 0) {_ks[k] = 0;
Continue
} _PK = (float) (double) _count/_mn);
_MK = 0;
for (int i = D; I <= K; i++) {float p = (float) (double) his[i]/_mn);
_PK + = p;
_MK = i * p;
} _ks[k] = (float) math.pow (_MG * _PK-_MK, 2)/(_PK * (1-_PK));
} _ks[0] = 0;
_max = _ks.max ();
for (int i = 0; i < 256; i++) { if (_ks[i] = = _max) _maxks.add (i);
int _k = (int) _maxks.average ();
return _k; }
To compute the HISTOGRAM function:
<summary>///picture Grayscale histogram calculation///</summary>///<param name= "image" > Picture </param
>///<param name= "Depth" > Depth </param>///<param name= "D" > to skip Grayscale </param>
<returns></returns> public static long[] Histogram (Mat image, int depth= 8,int d = 0) { if (image.
Numberofchannels!= 1) {throw new Exception ("channel must be 1");
}//Extract histogram------------------------------------long[] _his = new long[(int) Math.pow (2,depth)];
for (int i = D; i < (int) Math.pow (2, depth); i++) {_his[i] = 0; } unsafe {byte* data = (byte*) image.
Datapointer.topointer (); for (int row = 0; row < image. Height; row++) {//data = data + row * image.
Cols; for (int col = 0; Col < image. Width;
col++) {if (*data >= d) {
_his[*data]++;
} data++;
}} return _his; }
This is based on EMGUCV basic implementation functions.
Here's how it works:
Original Picture:
First, using the mean filter filter, and then the ordinary Otsu obtained is: the Boundary modified:
Original Picture:
General Otsu Processing Results: After the boundary is decorated: