17 #include <gsl/gsl_linalg.h>
18 #include <gsl/gsl_rng.h>
19 #include <GSLUtility.h>
24 #include "Selection.h"
29 Selection::Selection() {};
30 Selection::~Selection() {};
34 int Selection::elipticalReduction(Chip *selectionChip,
double percent_selected,
double play,
int patience_limit) {
53 std::vector < std::vector<int> > pts;
55 double dpt[2], random5[5][2];
57 unsigned long int randPt;
61 gsl_rng *rand_gen = gsl_rng_alloc(gsl_rng_taus);
62 gsl_rng_set( rand_gen, time(NULL) );
65 samples = selectionChip->Samples();
66 lines = selectionChip->Lines();
69 selectionEdge(selectionChip,&pts);
75 while (emptySets < patience_limit) {
78 randPt = gsl_rng_uniform_int( rand_gen ,pts.size());
79 random5[i][0] = pts[randPt][0];
80 random5[i][1] = pts[randPt][1];
84 if (!ellipseFrom5Pts(&ellNew,random5)) {
90 if ( ellNew.cen[0] < 1 || ellNew.cen[0] > samples || ellNew.cen[1] < 1 || ellNew.cen[1] > lines ) {
96 if (!bestFitEllipse(&ellNew, &pts, play, 50)) {
102 if (ellNew.area < ellBest.area) {
108 if (!ellipseInChip(&ellNew,selectionChip)) {
115 if (elipsePercentSelected(selectionChip,&ellNew) < percent_selected) {
124 ellBest.area = ellNew.area;
125 ellBest.A[0] = ellNew.A[0];
126 ellBest.A[1] = ellNew.A[1];
127 ellBest.A[2] = ellNew.A[2];
129 ellBest.cen[0] = ellNew.cen[0];
130 ellBest.cen[1] = ellNew.cen[1];
132 ellBest.semiMajor = ellNew.semiMajor;
133 ellBest.semiMinor = ellNew.semiMinor;
134 ellBest.majorAxis[0] = ellNew.majorAxis[0];
135 ellBest.majorAxis[1] = ellNew.majorAxis[1];
136 ellBest.minorAxis[0] = ellNew.minorAxis[0];
137 ellBest.minorAxis[1] = ellNew.minorAxis[1];
141 if (ellBest.area == 0)
145 for (i=1;i<=samples;i++) {
146 for (j=1;j<=lines;j++) {
150 if (!pointInEllipse(&ellBest,dpt,play)) {
152 selectionChip->SetValue(i,j,0.0);
166 int Selection::centerOfMass(Chip *selectionChip,
double *sample,
double *line) {
168 unsigned int samples, lines, i, j, n=0;
171 samples = selectionChip->Samples();
172 lines = selectionChip->Lines();
174 for (i=1;i<=samples;i++) {
175 for (j=1;j<=lines;j++) {
176 if (selectionChip->GetValue(i,j) == 1) {
184 *sample /= double(n);
189 int Selection::centerOfMassWeighted(Chip *inputChip, Chip *selectionChip,
double *sample,
double *line) {
192 int samples, lines,i, j;
194 samples = selectionChip->Samples();
195 if (inputChip->Samples() != samples) {
200 lines = selectionChip->Lines();
201 if (inputChip->Lines() != lines) {
211 for (i=1;i<=samples;i++) {
212 for (j=1;j<=lines;j++) {
213 if (selectionChip->GetValue(i,j) == 1) {
214 temp = inputChip->GetValue(i,j);
215 *sample += double(i)*temp;
216 *line += double(j)*temp;
230 std::vector<double> Selection::minimumBoundingElipse(std::vector< std::vector<int> > pts,
Ellipse *ell) {
237 std::vector<double> lamda(pts.size(),1.0/
double(pts.size()));
240 double delta,temp,ptc[2];
242 unsigned int niter=0;
248 ell->cen[0] = ell->cen[1] = 0.0;
249 for (i=0; i<pts.size(); i++) {
250 ell->cen[0] += pts[i][0]*lamda[i];
251 ell->cen[1] += pts[i][1]*lamda[i];
255 ell->A[0]=ell->A[1]=ell->A[2]=0.0;
256 for (i=0;i<pts.size();i++) {
257 ell->A[0] += pts[i][0] * pts[i][0] * lamda[i];
258 ell->A[1] += pts[i][0] * pts[i][1] * lamda[i];
259 ell->A[2] += pts[i][1] * pts[i][1] * lamda[i];
263 ell->A[0] = ell->A[2];
265 temp = ell->A[0]*ell->A[2] - ell->A[1]*ell->A[1];
273 for (i=0; i<pts.size(); i++) {
275 ptc[0] = pts[i][0] - ell->cen[0];
276 ptc[1] = pts[i][1] - ell->cen[1];
277 lamda[i] = ( (ptc[0]*ell->A[0] + ptc[1]*ell->A[1] )*ptc[0] + ( ptc[0]*ell->A[1] + ptc[1]*ell->A[2] )*ptc[1] )*lamda[i]/2.0;
278 delta += ( lamda[i] - temp )*( lamda[i] - temp );
282 }
while (delta > 1e-10 && niter < 500);
289 ellipseAxesAreaFromMatrix(ell);
294 double Selection::elipsePercentSelected(Chip *selectionChip,
Ellipse *ell) {
296 unsigned int lines, samples, i,j,
298 ellipsePixelsSelected=0,
299 outsideEllipsePixelsSelected=0;
302 lines = selectionChip->Lines();
303 samples = selectionChip->Samples();
307 for (i=1; i<=samples; i++) {
308 for (j=1; j<=lines; j++) {
311 if (pointInEllipse(ell, ptc, 0.0)) {
313 if (selectionChip->GetValue(i,j) == 1) ellipsePixelsSelected++;
317 if (selectionChip->GetValue(i,j) == 1) outsideEllipsePixelsSelected++;
326 if (
double(outsideEllipsePixelsSelected)/
double(outsideEllipsePixelsSelected+ellipsePixelsSelected) > 0.33)
return 0;
329 return double(ellipsePixelsSelected)/double(ellipsePixels)*100.0;
333 bool Selection::ellipseFrom5Pts(
Ellipse *ell,
double pts[5][2]) {
336 svdu[5][0]=svdu[5][1]=svdu[5][2]=svdu[5][3]=svdu[5][4]=svdu[5][5]=0.0;
338 double svdv[6][6],cubic[6],discriminant,delta, svdd[6];
342 gsl_matrix SVDVT,SVDU;
347 SVDU.data = &svdu[0][0];
353 SVDVT.data = &svdv[0][0];
363 svdu[i][3] = pts[i][0];
364 svdu[i][4] = pts[i][1];
366 svdu[i][0] = svdu[i][3]*svdu[i][3];
367 svdu[i][1] = svdu[i][3]*svdu[i][4];
368 svdu[i][2] = svdu[i][4]*svdu[i][4];
371 gsl_linalg_SV_decomp_jacobi(&SVDU,&SVDVT,&SVDD);
374 for (i=0;i<6;i++) cubic[i] = svdv[i][5];
377 discriminant = cubic[1]*cubic[1]-4*cubic[0]*cubic[2];
378 delta = (cubic[0]*cubic[2]-cubic[1]*cubic[1]/4.0)*cubic[5] + cubic[1]*cubic[4]*cubic[3]/4.0 - cubic[2]*cubic[3]*cubic[3]/4.0 - cubic[0]*cubic[4]*cubic[4]/4.0;
380 if( discriminant < 0 && delta < 0)
381 return this->ellipseFromCubic(ell,cubic);
387 bool Selection::ellipseFromCubic(
Ellipse *ell,
double cubic[6]) {
390 double discriminant,delta;
391 discriminant = cubic[1]*cubic[1]-4*cubic[0]*cubic[2];
392 delta = (cubic[0]*cubic[2]-cubic[1]*cubic[1]/4.0)*cubic[5] + cubic[1]*cubic[4]*cubic[3]/4.0 - cubic[2]*cubic[3]*cubic[3]/4.0 - cubic[0]*cubic[4]*cubic[4]/4.0;
394 if (discriminant > 0 || delta > 0)
return false;
397 ell->cen[0] = (-cubic[4]*cubic[1]+2*cubic[2]*cubic[3])/(cubic[1]*cubic[1] - 4*cubic[0]*cubic[2]);
398 ell->cen[1] = (cubic[4] + cubic[1]*ell->cen[0])/(-2*cubic[2]);
401 ell->A[0] = cubic[0];
402 ell->A[1] = cubic[1]/2.0;
403 ell->A[2] = cubic[2];
406 temp = (ell->A[0]*ell->cen[0]*ell->cen[0] + 2.0*ell->A[1]*ell->cen[0]*ell->cen[1] + ell->A[2]*ell->cen[1]*ell->cen[1] - cubic[5]);
412 ellipseAxesAreaFromMatrix(ell);
418 bool Selection::bestFitEllipse(
Ellipse *ell, std::vector < std::vector<int> > *pts,
double play,
unsigned int max_iter) {
465 double adot[5],bdot[2],mdot,wdot,ata[15],atf[5],dpt[2];
467 int iterFlag,i,j,k,l;
472 while (iterFlag && ni<max_iter) {
479 for (i=0,l=0; i<int((*pts).size()); i++) {
480 dpt[0] = (*pts)[i][0];
481 dpt[1] = (*pts)[i][1];
482 if (dpt[0]>150)
continue;
485 bdot[0] = 2*ell->A[0]*dpt[0] + 2*ell->A[1]*dpt[1] + -2.0*(ell->A[0]*ell->cen[0] + ell->A[1]*ell->cen[1]);
486 bdot[1] = 2*ell->A[2]*dpt[1] + 2*ell->A[1]*dpt[0] + -2.0*(ell->A[1]*ell->cen[0] + ell->A[2]*ell->cen[1]);
488 mdot = 1.0 / (bdot[0]*bdot[0] + bdot[1]*bdot[1]);
490 wdot = -( ell->A[0]*dpt[0]*dpt[0] +
491 2.0*ell->A[1]*dpt[0]*dpt[1] +
492 ell->A[2]*dpt[1]*dpt[1] +
493 -2.0*(ell->A[0]*ell->cen[0] + ell->A[1]*ell->cen[1])*dpt[0] +
494 -2.0*(ell->A[1]*ell->cen[0] + ell->A[2]*ell->cen[1])*dpt[1] +
495 (ell->A[0]*ell->cen[0]*ell->cen[0] + 2.0*ell->A[1]*ell->cen[0]*ell->cen[1] + ell->A[2]*ell->cen[1]*ell->cen[1] -1.0) );
497 if (fabs(wdot*sqrt(mdot)) > play)
continue;
501 adot[0] = dpt[0]*dpt[0] + -2.0*ell->cen[0]*dpt[0] + ell->cen[0]*ell->cen[0];
502 adot[1] = 2.0*dpt[0]*dpt[1] - 2.0*ell->cen[1]*dpt[0] -2.0*ell->cen[0]*dpt[1] + 2.0*ell->cen[0]*ell->cen[1];
503 adot[2] = dpt[1]*dpt[1] + -2.0*ell->cen[1]*dpt[1] + ell->cen[1]*ell->cen[1];
510 ata[isymp(j,k)] += adot[j]*mdot*adot[k];
514 atf[j] += mdot*adot[j]*wdot;
517 if (l<5)
return false;
520 if (choleski_solve(ata,atf,5,2) != 1)
return false;
527 ell->cen[0] += atf[3];
528 ell->cen[1] += atf[4];
532 if (fabs(atf[i]) > 0.001) {
545 if (atf[i] != atf[i])
return false;
551 return ellipseAxesAreaFromMatrix(ell);
555 void Selection::selectionEdge(Chip *selectionChip, std::vector < std::vector <int> > *pts) {
560 std::vector <int> pt(2);
561 int i,j,k,l,nUS,lines,samples;
563 samples = selectionChip->Samples();
564 lines = selectionChip->Lines();
565 for (i=2;i<samples;i++) {
566 for (j=2;j<lines;j++) {
568 for (k=i-1,nUS=0;k<=i+1;k++)
569 for (l=j-1;l<=j+1;l++)
570 if (selectionChip->GetValue(k,l) == 0 && k != l) nUS++;
572 if (nUS > 0 && selectionChip->GetValue(i,j) == 1) {
575 (*pts).push_back(pt);
583 bool Selection::ellipseAxesAreaFromMatrix(
Ellipse *ell) {
589 temp = ell->A[0]*ell->A[2] - ell->A[1]*ell->A[1];
591 Ai[0] = ell->A[2]/temp;
592 Ai[1] = -ell->A[1]/temp;
593 Ai[2] = ell->A[0]/temp;
597 temp = -(Ai[0] + Ai[2]);
598 temp = -0.5*(temp + ((temp>=0) - (temp<0))*sqrt(temp*temp - 4.0*(Ai[0]*Ai[2]-Ai[1]*Ai[1])));
600 ell->semiMajor = temp;
601 ell->semiMinor = (Ai[0]*Ai[2]-Ai[1]*Ai[1])/temp;
603 if (ell->semiMajor < 0 || ell->semiMinor < 0)
return false;
605 if (ell->semiMajor < ell->semiMinor) {
606 temp= ell->semiMajor;
607 ell->semiMajor = ell->semiMinor;
608 ell->semiMinor = temp;
616 temp = atan2(Ai[0]-ell->semiMajor,-Ai[1]);
617 ell->majorAxis[0] = cos(temp);
618 ell->majorAxis[1] = sin(temp);
620 temp = atan2(Ai[0]-ell->semiMinor, -Ai[1]);
621 ell->minorAxis[0] = cos(temp);
622 ell->minorAxis[1] = sin(temp);
624 ell->semiMajor = sqrt(ell->semiMajor);
625 ell->semiMinor = sqrt(ell->semiMinor);
628 ell->area = ell->semiMajor*ell->semiMinor*acos(-1.0);
634 bool Selection::ellipseInChip(
Ellipse *ell, Chip *chip) {
637 double pt[4][2],vec[2],temp;
641 samples = chip->Samples();
642 lines = chip->Lines();
644 if (ell->cen[0] < 1 || ell->cen[0] > samples || ell->cen[1] < 1 || ell->cen[1] > lines)
return false;
647 pt[0][0] = 1-ell->cen[0];
648 pt[0][1] = 1-ell->cen[1];
650 pt[1][0] = 1-ell->cen[0];
651 pt[1][1] = double(lines)-ell->cen[1];
653 pt[2][0] = double(samples)-ell->cen[0];
654 pt[2][1] = double(lines)-ell->cen[1];
656 pt[3][0] = double(samples)-ell->cen[0];
657 pt[3][1] = 1-ell->cen[1];
666 pt[0][0] = ell->majorAxis[0] * temp + ell->majorAxis[1] * pt[0][1];
667 pt[0][1] = -ell->majorAxis[1] * temp + ell->majorAxis[0] * pt[0][1];
669 pt[1][0] = ell->majorAxis[0] * temp + ell->majorAxis[1] * pt[1][1];
670 pt[1][1] = -ell->majorAxis[1] * temp + ell->majorAxis[0] * pt[1][1];
673 pt[2][0] = ell->majorAxis[0] * temp + ell->majorAxis[1] * pt[2][1];
674 pt[2][1] = -ell->majorAxis[1] * temp + ell->majorAxis[0] * pt[2][1];
677 pt[3][0] = ell->majorAxis[0] * temp + ell->majorAxis[1] * pt[3][1];
678 pt[3][1] = -ell->majorAxis[1] * temp + ell->majorAxis[0] * pt[3][1];
682 pt[i][0] /= ell->semiMajor;
683 pt[i][1] /= ell->semiMinor;
688 vec[0] = pt[1][0] - pt[0][0];
689 vec[1] = pt[1][1] - pt[0][1];
690 temp = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
694 temp = fabs(vec[0]*pt[0][1] - vec[1]*pt[0][0]);
695 if (temp < 1.0)
return false;
698 vec[0] = pt[2][0] - pt[1][0];
699 vec[1] = pt[2][1] - pt[1][1];
700 temp = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
704 temp = fabs(vec[0]*pt[1][1] - vec[1]*pt[1][0]);
706 if (temp < 1.0)
return false;
709 vec[0] = pt[3][0] - pt[2][0];
710 vec[1] = pt[3][1] - pt[2][1];
711 temp = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
715 temp = fabs(vec[0]*pt[2][1] - vec[1]*pt[2][0]);
717 if (temp < 1.0)
return false;
720 vec[0] = pt[0][0] - pt[3][0];
721 vec[1] = pt[0][1] - pt[3][1];
722 temp = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
726 temp = fabs(vec[0]*pt[3][1] - vec[1]*pt[3][0]);
727 if (temp < 1.0)
return false;
732 bool Selection::pointInEllipse(
Ellipse *ell,
double pt[2],
double play) {
736 double bdot[2],mdot,wdot;
738 bdot[0] = 2*ell->A[0]*pt[0] + 2*ell->A[1]*pt[1] + -2.0*(ell->A[0]*ell->cen[0] + ell->A[1]*ell->cen[1]);
739 bdot[1] = 2*ell->A[2]*pt[1] + 2*ell->A[1]*pt[0] + -2.0*(ell->A[1]*ell->cen[0] + ell->A[2]*ell->cen[1]);
740 mdot = 1.0 / (bdot[0]*bdot[0] + bdot[1]*bdot[1]);
742 wdot = ( ell->A[0]*pt[0]*pt[0] +
743 2.0*ell->A[1]*pt[0]*pt[1] +
744 ell->A[2]*pt[1]*pt[1] +
745 -2.0*(ell->A[0]*ell->cen[0] + ell->A[1]*ell->cen[1])*pt[0] +
746 -2.0*(ell->A[1]*ell->cen[0] + ell->A[2]*ell->cen[1])*pt[1] +
747 (ell->A[0]*ell->cen[0]*ell->cen[0] + 2.0*ell->A[1]*ell->cen[0]*ell->cen[1] + ell->A[2]*ell->cen[1]*ell->cen[1] -1.0) );
749 if (wdot*sqrt(mdot) > play)
return false;
755 bool Selection::ellipseFromCenterAxesAngle(
Ellipse *ell,
double centerSample,
double centerLine,
double semiMajor,
double semiMinor,
double theta) {
766 if (semiMajor < semiMinor)
return false;
770 ell->semiMajor = semiMajor;
771 ell->semiMinor = semiMinor;
772 ell->majorAxis[0] = cos(theta);
773 ell->majorAxis[1] = sin(theta);
774 ell->minorAxis[0] = -ell->majorAxis[1];
775 ell->minorAxis[1] = -ell->majorAxis[0];
776 ell->cen[0] = centerSample;
777 ell->cen[1] = centerLine;
779 Ai[0] = ell->majorAxis[0]*ell->majorAxis[0]*ell->semiMajor*ell->semiMajor + ell->majorAxis[1]*ell->majorAxis[1]*ell->semiMinor*ell->semiMinor;
780 Ai[2] = ell->majorAxis[1]*ell->majorAxis[1]*ell->semiMajor*ell->semiMajor + ell->majorAxis[0]*ell->majorAxis[0]*ell->semiMinor*ell->semiMinor;
782 Ai[1] = ell->majorAxis[0]*ell->majorAxis[1]*(ell->semiMajor*ell->semiMajor - ell->semiMinor*ell->semiMinor);
784 temp = Ai[0]*Ai[2] + Ai[1]*Ai[1];
786 ell->A[0] = Ai[2]/temp;
787 ell->A[1] = -Ai[1]/temp;
788 ell->A[2] = Ai[0]/temp;
790 ell->area = semiMajor*semiMinor*acos(-1.0);