Divide the pixels with similar colors in an image into a group, and replace the color of those pixels with the group average value.
Create a relatively small BMP image, such as less than 128*128, or the running time may be a little long.
Use the followingCodeExport pixel information to TXT:
Code
Static Void BMP totxt ( String Path)
{
Using (Streamwriter SW = New Streamwriter ( " Result.txt " ))
{
VaR img = New Bitmap (PATH );
Sw. writeline ( " Dimension: {0} X {1} " , IMG. Width, IMG. Height );
For ( Int I = 0 ; I < IMG. width; I ++ )
{
For ( Int J = 0 ; J < IMG. height; j ++ )
{
VaR pix = IMG. getpixel (I, j );
Sw. writeline ( " {0} {1} {2} " , Pix. R, pix. G, pix. B );
}
}
}
}
Copy the output file as result. Data and remove the first line (image size information ).
Then use the following SCILAB code to perform meanshift on the data:
// ------------ Helper functions -----------------
Function [feature, CLS] = readdatapoint (mat, I, fieldcount, classification) // put the ith row of Mat into a list
If classification = 0 then
Feature = zeros (fieldcount, 1 );
For j = 1: fieldcount
Feature (j) = MAT (I, j );
End
CLS =-1; // not used for clustering
Else
Feature = zeros (fieldcount-1, 1 );
For j = 1: fieldcount-1
Feature (j) = MAT (I, j );
End
CLS = MAT (I, fieldcount );
End
Endfunction
Function data = retrievedata (filepath, strfamat, classification)
If ("string" <> typeof (filepath) then
Error ("filepath must be a string .");
End
FID = mopen (filepath, "R ");
If (FID =-1)
Error ("can not open data file:" + filepath );
End
Records = mfscanf (-1, FID, strfamat );
Recsize = size (records );
Reccount = recsize (1 );
Fieldcount = recsize (2 );
Data = List ();
For I = 1: reccount
[Feature, CLS] = readdatapoint (records, I, fieldcount, classification );
Data ($ + 1) = struct ("ID", I, "feature", feature, "CLS", CLS, "comment", 1 );
End
Mclose (FID );
Endfunction
Function setsd () // reset Random Seed
Dt = getdate ();
Newseed = DT (3) * DT (9) ^ 2 + dt (10 );
Grand ("setsd", newseed );
Endfunction
// ------------ Core functions -----------------
// Compute mean shift, require global variable datapoints, N, FLEN
Function M = calcms (Y, H)
Upper = zeros (FLEN, 1 );
Lower = 0;
For I = 1: N
Xi = datapoints (I). feature;
Smallkarg = (Y-xi)/h;
Temp =-exp (-sum (smallkarg. * smallkarg)/2)/2;
Lower = Lower + temp;
Upper = upper + temp * XI;
End
M = Lower ^-1 * upper-y;
Endfunction
// Stop if the distance between two Yi and yi + 1 <threshold
Function Y = converge (XI, H, threshold)
Y = XI;
Oldy = Y + 10000;
While norm (Y-Oldy)> threshold
Oldy = y;
Y = Y + calcms (Y, H );
End
Endfunction
// Require global var datapoints
Function Clusters = runmeanshift (H, threshold, aggregatedistance)
Pointcount = size (datapoints );
Clusters = List ();
For I = 1: pointcount
Pcount = I;
Y = converge (datapoints (I). feature, H, threshold );
Clustercount = size (clusters );
Clusterid = 0; // Aven't put in a cluster
Clusterdistance = aggregatedistance; // a variable help to select the best Cluster
For j = 1: clustercount
Distance = norm (clusters (j). Len ^-1 * clusters (j). sigmay-y); // distance to cluster center
If distance <= clusterdistance then // within cluster radius
Clusterdistance = distance;
Clusterid = J;
End
End
If clusterid = 0 then // put in a new cluster
Clusters ($ + 1) = struct ("sigmay", 0, "len", 1, "elements", list (), "CLS",-1 );
Clusters ($). sigmay = y;
Clusters ($). Elements ($ + 1) = struct ("ID", I, "Y", y );
Else
Clusters (clusterid). sigmay = clusters (clusterid). sigmay + Y;
Clusters (clusterid). Len = clusters (clusterid). Len + 1;
Clusters (clusterid). Elements ($ + 1) = struct ("ID", I, "Y", y );
End
End
Endfunction
// Require global clusters and datapoints
Function createbmptxt (filepath)
Pointnumber = size (datapoints );
Pixellist = zeros (pointnumber, 3 );
Clustercount = size (clusters );
For I = 1: clustercount
Clusterlength = clusters (I). Len;
Clustermean = clusters (I). Len ^-1 * clusters (I). sigmay;
Clustermean = clustermean ';
For j = 1: clusterlength
Pixellist (clusters (I). Elements (j). ID, :) = clustermean;
End
End
FID = mopen (filepath, "W ");
If (FID =-1)
Error ("can not open data file:" + filepath );
End
For I = 1: pointnumber
Mfprintf (FID, "% d \ n", pixellist (I ,:));
End
Mclose (FID );
Endfunction
Stacksize ('max ');
// Image Process Code ----------------------
Function testimg ()
Datapoints = retrievedata ("D: \ result. Data", "% d", 0 );
FLEN = size (datapoints (1). feature );
FLEN = FLEN (1 );
N = size (datapoints );
Clusters = runmeanshift (1, 50, 50 );
Createbmptxt ("D: \ shiftedimg.txt ");
Endfunction
Testimg ();
You can adjust the first parameter of the runmeanshift function to change the image effect. The larger the parameter, the smaller the number of colors generated for the image.
The above code can be fully implemented using C #, and C # can use Brahma for GPU acceleration. In scilib, matrix operations are very convenient, but the performance seems to be a problem.
In the first line of shiftedimg.txt, insert the size information of the image again, in the same format as result.txt. Then, use the following code to convert the text file back to BMP:
Code
Static Void Txttobmp ( String Path)
{
Using (Streamreader SR = New Streamreader (PATH ))
{
String Line = Sr. Readline ();
Int Ind1 = Line. indexof ( " : " );
Int Ind2 = Line. indexof ( " X " );
Int Width = Int . Parse (line. substring (ind1 + 1 , Ind2 - Ind1 - 1 ));
Int Height = Int . Parse (line. substring (ind2 + 1 ));
Bitmap BMP = New Bitmap (width, height );
Int Linecount = 0 ;
While (Line = Sr. Readline ()) ! = Null )
{
String [] Parts = Line. Split ( ' ' );
Int R = ( Int ) Math. Round ( Double . Parse (parts [ 0 ]);
Int G = ( Int ) Math. Round ( Double . Parse (parts [ 1 ]);
Int B = ( Int ) Math. Round ( Double . Parse (parts [ 2 ]);
BMP. setpixel (linecount / Height, linecount % Height, color. fromargb (R, G, B ));
Linecount ++ ;
}
BMP. Save ( " Result.bmp " );
}
}
Finally, let's take a look at the comparison:
->