iPiano
An implementation of the iPiano algorithms for non-convex and non-smooth optimization.
 All Classes Functions Variables
functionals.h
1 
42 #ifndef FUNCTIONALS_H
43 #define FUNCTIONALS_H
44 
45 #include <Eigen/Dense>
46 #include <Eigen/Core>
47 #include <opencv2/opencv.hpp>
48 #include <glog/logging.h>
49 
55 {
56 public:
57 
59  class Util
60  {
61  public:
62 
67  static void convertEigenToOpenCV(const Eigen::MatrixXf &eigen, cv::Mat &opencv);
68 
73  static void convertOpenCVToEigen(const cv::Mat &opencv, Eigen::MatrixXf &eigen);
74 
79  static void convertEigenToOpenCV_Color(const Eigen::MatrixXf &eigen, cv::Mat &opencv);
80 
85  static void convertOpenCVToEigen_Color(const cv::Mat &opencv, Eigen::MatrixXf &eigen);
86  };
87 
89  class Denoising
90  {
91  public:
92 
94  class Noise
95  {
96  public:
97 
103  static void addGaussianAdditive(const Eigen::MatrixXf &image, float sigma,
104  Eigen::MatrixXf &noisy_image);
105 
111  static void addSaltPepper(const Eigen::MatrixXf &image, float p,
112  Eigen::MatrixXf &noisy_image);
113  };
114 
117  {
118  public:
124  static float computePSNR(const Eigen::MatrixXf &image,
125  const Eigen::MatrixXf &denoised_image, float range = 1);
126  };
127 
133  static float f_lorentzianPairwise(const Eigen::MatrixXf &x, float sigma,
134  float lambda);
135 
142  static void df_lorentzianPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
143  float sigma, float lambda);
144 
150  static float f_squaredPairwise(const Eigen::MatrixXf &x, float lambda);
151 
158  static void df_squaredPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
159  float lambda);
160 
166  static float f_smoothAbsolutePairwise(const Eigen::MatrixXf &x, float epsilon,
167  float lambda);
168 
175  static void df_smoothAbsolutePairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
176  float epsilon, float lambda);
177 
183  static float g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0);
184 
191  static void prox_g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
192  Eigen::MatrixXf &prox_f_x, float alpha);
193 
199  static float g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0);
200 
207  static void prox_g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
208  Eigen::MatrixXf &prox_f_x, float alpha);
209 
210  };
211 
218  {
219  public:
220 
225  static float f(const Eigen::MatrixXf &x, float epsilon);
226 
232  static void df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
233  float epsilon);
234 
243  static float g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
244  float Cp, float Cm, float lambda);
245 
256  static void prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
257  Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda,
258  float alpha);
259 
268  static float g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &X_0,
269  float Cp, float Cm, float lambda);
270 
281  static void prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
282  Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda,
283  float alpha);
284 
289  static float Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0);
290 
295  static float Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0);
296  };
297 
304  {
305  public:
306 
311  static float f(const Eigen::MatrixXf &x, float epsilon);
312 
318  static void df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
319  float epsilon);
320 
329  static float g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
330  const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda);
331 
342  static void prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
343  Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp,
344  const Eigen::Vector3f &Cm, float lambda, float alpha);
345 
354  static float g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &X_0,
355  const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda);
356 
367  static void prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
368  Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm,
369  float lambda, float alpha);
370 
376  static void Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::Vector3f &Cp);
377 
383  static void Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::Vector3f &Cm);
384  };
385 
392  {
393  public:
398  static float f(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A,
399  const Eigen::MatrixXf &y, float lambda);
400 
406  static void df(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A,
407  const Eigen::MatrixXf &y, Eigen::MatrixXf &df_x, float lambda);
408 
417  static float g(const Eigen::MatrixXf &x);
418 
429  static void prox_g(const Eigen::MatrixXf &x, Eigen::MatrixXf &prox_g_x,
430  float alpha);
431  };
432 };
433 
435 // Functionals::Util::convertEigenToOpenCV
437 
438 void Functionals::Util::convertEigenToOpenCV(const Eigen::MatrixXf &matrix, cv::Mat &image)
439 {
440  image.create(matrix.rows(), matrix.cols(), CV_32FC1);
441 
442  for (int i = 0; i < image.rows; i++)
443  {
444  for (int j = 0; j < image.cols; j++)
445  {
446  image.at<float>(i, j) = matrix(i, j);
447  }
448  }
449 }
450 
452 // Functionals::Util::convertOpenCVToEigen
454 
455 void Functionals::Util::convertOpenCVToEigen(const cv::Mat &image, Eigen::MatrixXf &matrix)
456 {
457  LOG_IF(FATAL, image.type() != CV_32FC1) << "Invalid image type.";
458  LOG_IF(FATAL, image.channels() != 1) << "Only one channel supported, use convertOpenCVToEigen_Color instead!";
459 
460  matrix = Eigen::MatrixXf(image.rows, image.cols);
461 
462  for (int i = 0; i < image.rows; i++)
463  {
464  for (int j = 0; j < image.cols; j++)
465  {
466  matrix(i, j) = image.at<float>(i, j);
467  }
468  }
469 }
470 
472 // Functionals::Util::convertEigenToOpenCV
474 
475 void Functionals::Util::convertEigenToOpenCV_Color(const Eigen::MatrixXf &matrix, cv::Mat &image)
476 {
477  LOG_IF(FATAL, matrix.rows()%3 != 0) << "Eigen matrix expected to encode a color OpenCV matrix, i.e. number of rows needs to be divisible by three!";
478 
479  image.create(matrix.rows()/3, matrix.cols(), CV_32FC3);
480 
481  for (int i = 0; i < image.rows; i++)
482  {
483  for (int j = 0; j < image.cols; j++)
484  {
485  image.at<cv::Vec3f>(i, j)[0] = matrix(i, j);
486  image.at<cv::Vec3f>(i, j)[1] = matrix(image.rows + i, j);
487  image.at<cv::Vec3f>(i, j)[2] = matrix(2*image.rows + i, j);
488  }
489  }
490 }
491 
493 // Functionals::Util::convertOpenCVToEigen
495 
496 void Functionals::Util::convertOpenCVToEigen_Color(const cv::Mat &image, Eigen::MatrixXf &matrix)
497 {
498  LOG_IF(FATAL, image.type() != CV_32FC3) << "Invalid image type.";
499  LOG_IF(FATAL, image.channels() != 3) << "Only three channels supported, use convertOpenCVToEigen instead!";
500 
501  matrix = Eigen::MatrixXf(3*image.rows, image.cols);
502 
503  for (int i = 0; i < image.rows; i++)
504  {
505  for (int j = 0; j < image.cols; j++)
506  {
507  matrix(i, j) = image.at<cv::Vec3f>(i, j)[0];
508  matrix(image.rows + i, j) = image.at<cv::Vec3f>(i, j)[1];
509  matrix(2*image.rows + i, j) = image.at<cv::Vec3f>(i, j)[2];
510  }
511  }
512 }
513 
515 // Functionals::Noise::addGaussianAdditive
517 
518 void Functionals::Denoising::Noise::addGaussianAdditive(const Eigen::MatrixXf &image,
519  float sigma, Eigen::MatrixXf &noisy_image)
520 {
521  std::random_device random;
522  std::mt19937 generator(random());
523  std::normal_distribution<float> gaussian(0, sigma);
524 
525  noisy_image = Eigen::MatrixXf::Zero(image.rows(), image.cols());
526  for (int i = 0; i < image.rows(); i++)
527  {
528  for (int j = 0; j < image.cols(); j++)
529  {
530  noisy_image(i, j) = image(i, j) + gaussian(generator);
531  }
532  }
533 }
534 
536 // Functionals::Noise::addSaltPepper
538 
539 void Functionals::Denoising::Noise::addSaltPepper(const Eigen::MatrixXf &image,
540  float p, Eigen::MatrixXf &noisy_image)
541 {
542 
543 }
544 
546 // Functionals::Denoising::Evaluation::computePSNR
548 
549 float Functionals::Denoising::Evaluation::computePSNR(const Eigen::MatrixXf &image,
550  const Eigen::MatrixXf &denoised_image, float range)
551 {
552  LOG_IF(FATAL, image.rows() != denoised_image.rows() || image.cols() != denoised_image.cols())
553  << "Image dimensions do not match!";
554  LOG_IF(FATAL, image.rows() == 0 || image.cols() == 0)
555  << "Image empty.";
556 
557  float psnr = 0;
558 
559  // Compute mse.
560  for (int i = 0; i < image.rows(); i++)
561  {
562  for (int j = 0; j < image.cols(); j++)
563  {
564  psnr += (image(i, j) - denoised_image(i, j))*(image(i, j) - denoised_image(i, j));
565  }
566  }
567 
568  psnr /= image.rows()*image.cols();
569  psnr = 10*std::log(range/psnr)/std::log(10);
570 
571  return psnr;
572 }
573 
575 // Functionals::Denoising::f_lorentzianPairwise
577 
578 float rho(float z, float sigma)
579 {
580  return std::log(1.f + 1.f/2.f*(z*z)/(sigma*sigma));
581 }
582 
583 float Functionals::Denoising::f_lorentzianPairwise(const Eigen::MatrixXf &x, float sigma, float lambda)
584 {
585  float f = 0;
586 
587  for (int i = 0; i < x.rows(); i++)
588  {
589  for (int j = 0; j < x.cols(); j++)
590  {
591  if (i > 0)
592  {
593  f += lambda*rho(x(i, j) - x(i - 1, j), sigma);
594  }
595 
596  if (j > 0)
597  {
598  f += lambda*rho(x(i, j) - x(i, j - 1), sigma);
599  }
600  }
601  }
602 
603  return f;
604 }
605 
607 // Functionals::Denoising::df_lorentzianPairwise
609 
610 float drho(float z, float sigma)
611 {
612  return 1.f/(1.f + 1.f/2.f*(z*z)/(sigma*sigma))*(z/(sigma*sigma));
613 }
614 
615 void Functionals::Denoising::df_lorentzianPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
616  float sigma, float lambda)
617 {
618  df_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
619 
620  for (int i = 0; i < x.rows(); i++)
621  {
622  for (int j = 0; j < x.cols(); j++)
623  {
624  if (i > 0)
625  {
626  df_x(i, j) += lambda*drho(x(i, j) - x(i - 1, j), sigma);
627  }
628 
629  if (j > 0)
630  {
631  df_x(i, j) += lambda*drho(x(i, j) - x(i, j - 1), sigma);
632  }
633 
634  if (i < x.rows() - 1)
635  {
636  df_x(i, j) -= lambda*drho(x(i + 1, j) - x(i, j), sigma);
637  }
638 
639  if (j < x.cols() - 1)
640  {
641  df_x(i, j) -= lambda*drho(x(i, j + 1) - x(i, j), sigma);
642  }
643  }
644  }
645 }
646 
648 // Functionals::Denoising::f_squaredPairwise
650 
651 float Functionals::Denoising::f_squaredPairwise(const Eigen::MatrixXf &x, float lambda)
652 {
653  float f = 0;
654 
655  for (int i = 0; i < x.rows(); i++)
656  {
657  for (int j = 0; j < x.cols(); j++)
658  {
659  if (i > 0)
660  {
661  f += lambda*(x(i, j) - x(i - 1, j))*(x(i, j) - x(i - 1, j));
662  }
663 
664  if (j > 0)
665  {
666  f += lambda*(x(i, j) - x(i, j - 1))*(x(i, j) - x(i, j - 1));
667  }
668  }
669  }
670 
671  return f;
672 }
673 
675 // Functionals::Denoising::df_squaredPairwise
677 
678 void Functionals::Denoising::df_squaredPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
679  float lambda)
680 {
681  df_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
682 
683  for (int i = 0; i < x.rows(); i++)
684  {
685  for (int j = 0; j < x.cols(); j++)
686  {
687  if (i > 0)
688  {
689  df_x(i, j) += lambda*2*(x(i, j) - x(i - 1, j));
690  }
691 
692  if (j > 0)
693  {
694  df_x(i, j) += lambda*2*(x(i, j) - x(i, j - 1));
695  }
696 
697  if (i < x.rows() - 1)
698  {
699  df_x(i, j) -= lambda*2*(x(i + 1, j) - x(i, j));
700  }
701 
702  if (j < x.cols() - 1)
703  {
704  df_x(i, j) -= lambda*2*(x(i, j + 1) - x(i, j));
705  }
706  }
707  }
708 }
709 
711 // Functionals::Denoising::g_absoluteUnary
713 
714 float Functionals::Denoising::g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
715 {
716  float g = 0;
717 
718  for (int i = 0; i < x.rows(); i++)
719  {
720  for (int j = 0; j < x.cols(); j++)
721  {
722  g += std::abs(x(i, j) - x_0(i, j));
723  }
724  }
725 
726  return g;
727 }
728 
730 // Functionals::Denoising::prox_g_absoluteUnary
732 
733 // http://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
734 template <typename T>
735 int sign(T val) {
736  return (T(0) < val) - (val < T(0));
737 }
738 
739 void Functionals::Denoising::prox_g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
740  Eigen::MatrixXf &prox_g_x, float alpha)
741 {
742  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
743 
744  for (int i = 0; i < x.rows(); i++)
745  {
746  for (int j = 0; j < x.cols(); j++)
747  {
748  prox_g_x(i, j) = std::max(0.f, std::abs(x(i, j) - x_0(i, j)) - alpha)*sign(x(i, j) - x_0(i, j)) + x_0(i, j);
749  }
750  }
751 }
752 
754 // Functionals::Denoising::g_squaredUnary
756 
757 float Functionals::Denoising::g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
758 {
759  float g = 0;
760 
761  for (int i = 0; i < x.rows(); i++)
762  {
763  for (int j = 0; j < x.cols(); j++)
764  {
765  g += (x(i, j) - x_0(i, j))*(x(i, j) - x_0(i, j));
766  }
767  }
768 
769  return g;
770 }
771 
773 // Functionals::Denoising::prox_g_squaredUnary
775 
776 void Functionals::Denoising::prox_g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
777  Eigen::MatrixXf &prox_g_x, float alpha)
778 {
779  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
780 
781  for (int i = 0; i < x.rows(); i++)
782  {
783  for (int j = 0; j < x.cols(); j++)
784  {
785  prox_g_x(i, j) = (x(i, j) + alpha*x_0(i, j))/(1 + alpha);
786  }
787  }
788 }
789 
791 // Functionals::PhaseField::f
793 
794 float Functionals::PhaseField::f(const Eigen::MatrixXf &x, float epsilon)
795 {
796  float f_x = 0;
797 
798  for (int i = 0; i < x.rows(); i++)
799  {
800  for (int j = 0; j < x.cols(); j++)
801  {
802  if (i > 0)
803  {
804  f_x += epsilon*(x(i - 1, j) - x(i, j))*(x(i - 1, j) - x(i, j));
805  }
806 
807  if (j > 0)
808  {
809  f_x += epsilon*(x(i, j - 1) - x(i, j))*(x(i, j - 1) - x(i, j));
810  }
811 
812  f_x += (1 - x(i, j)*x(i, j))*(1 - x(i, j)*x(i, j))/epsilon;
813  }
814  }
815 
816  return f_x;
817 }
818 
820 // Functionals::PhaseField::df
822 
823 void Functionals::PhaseField::df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
824  float epsilon)
825 {
826  df_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
827 
828  for (int i = 0; i < x.rows(); i++)
829  {
830  for (int j = 0; j < x.cols(); j++)
831  {
832  df_x(i, j) = - 4*(1 - x(i, j)*x(i, j))*x(i, j)/epsilon;
833 
834  if (i > 0)
835  {
836  df_x(i, j) -= 2*epsilon*(x(i - 1, j) - x(i, j));
837  }
838 
839  if (j > 0)
840  {
841  df_x(i, j) -= 2*epsilon*(x(i, j - 1) - x(i, j));
842  }
843 
844  if (i < x.rows() - 1)
845  {
846  df_x(i, j) += 2*epsilon*(x(i, j) - x(i + 1, j));
847  }
848 
849  if (j < x.cols() - 1)
850  {
851  df_x(i, j) += 2*epsilon*(x(i, j) - x(i, j + 1));
852  }
853  }
854  }
855 }
856 
858 // Functionals::PhaseField::g
860 
861 float Functionals::PhaseField::g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
862  float Cp, float Cm, float lambda)
863 {
864  float g_x = 0;
865 
866  for (int i = 0; i < x.rows(); i++)
867  {
868  for (int j = 0; j < x.cols(); j++)
869  {
870  g_x += (1 + x(i, j))*(1 + x(i, j))*(x_0(i, j) - Cp)*(x_0(i, j) - Cp)/4
871  + (1 - x(i, j))*(1 - x(i, j))*(x_0(i, j) - Cm)*(x_0(i, j) - Cm)/4;
872  }
873  }
874 
875  return lambda*g_x;
876 }
877 
879 // Functionals::PhaseField::prox_g
881 
882 void Functionals::PhaseField::prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
883  Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda, float alpha)
884 {
885  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
886 
887  for (int i = 0; i < x.rows(); i++)
888  {
889  for (int j = 0; j < x.cols(); j++)
890  {
891  float cp = (x_0(i, j) - Cp)*(x_0(i, j) - Cp);
892  float cm = (x_0(i, j) - Cm)*(x_0(i, j) - Cm);
893 
894  prox_g_x(i, j) = (x(i, j) - lambda*alpha*cp/2 + lambda*alpha*cm/2)
895  /(1 + lambda*alpha*cp/2 + lambda*alpha*cm/2);
896  }
897  }
898 }
899 
901 // Functionals::PhaseField::g
903 
904 float Functionals::PhaseField::g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
905  float Cp, float Cm, float lambda)
906 {
907  float g_x = 0;
908 
909  for (int i = 0; i < x.rows(); i++)
910  {
911  for (int j = 0; j < x.cols(); j++)
912  {
913  float cp = std::abs(x_0(i, j) - Cp);
914  float cm = std::abs(x_0(i, j) - Cm);
915 
916  g_x += std::abs(1 + x(i, j))*cp + std::abs(1 - x(i, j))*cm;
917  }
918  }
919 
920  return lambda*g_x;
921 }
922 
924 // Functionals::PhaseField::prox_g
926 
927 void Functionals::PhaseField::prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
928  Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda, float alpha)
929 {
930  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
931 
932  for (int i = 0; i < x.rows(); i++)
933  {
934  for (int j = 0; j < x.cols(); j++)
935  {
936  float cp = alpha*lambda*std::abs(x_0(i, j) - Cp);//*(x_0(i, j) - Cp);
937  float cm = alpha*lambda*std::abs(x_0(i, j) - Cm);//*(x_0(i, j) - Cm);
938 
939  if (x(i, j) > 1 + (cp + cm))
940  {
941  prox_g_x(i, j) = -(cp + cm) + x(i, j);
942  }
943  else if (x(i, j) >= 1 + (cp - cm) && x(i, j) <= 1 + (cp + cm))
944  {
945  prox_g_x(i, j) = 1;
946  }
947  else if (x(i, j) > -1 + (cp - cm) && x(i, j) < 1 + (cp - cm))
948  {
949  prox_g_x(i, j) = (-cp + cm) + x(i, j);
950  }
951  else if (x(i, j) >= -1 - (cp + cm) && x(i, j) <= -1 + (cp - cm))
952  {
953  prox_g_x(i, j) = -1;
954  }
955  else
956  {
957  LOG_IF(FATAL, x(i, j) >= -1 - (cp + cm)) << "Invalid case in PhaseField::prox_g_absolute!";
958  prox_g_x(i, j) = (cp + cm) + x(i, j);
959  }
960 
961 // std::cout << -1 - (cp + cm) << "," << -1 + (cp - cm) << "," << 1 + (cp - cm) << "," << 1 + (cp + cm) << std::endl;
962  }
963  }
964 }
965 
967 // Functionals::PhaseField::Cp
969 
970 float Functionals::PhaseField::Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
971 {
972  float Cp_nom = 0;
973  float Cp_denom = 0;
974 
975  for (int i = 0; i < x.rows(); i++)
976  {
977  for (int j = 0; j < x.cols(); j++)
978  {
979 // if (x(i, j) > 0)
980 // {
981  Cp_nom += (1 + x(i, j))*(1 + x(i, j))*x_0(i, j);
982  Cp_denom += (1 + x(i, j))*(1 + x(i, j));
983 // }
984  }
985  }
986 
987  if (Cp_denom > 0)
988  {
989  Cp_nom /= Cp_denom;
990  }
991 
992  return Cp_nom;
993 }
994 
996 // Functionals::PhaseField::Cm
998 
999 float Functionals::PhaseField::Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
1000 {
1001  float Cm_nom = 0;
1002  float Cm_denom = 0;
1003 
1004  for (int i = 0; i < x.rows(); i++)
1005  {
1006  for (int j = 0; j < x.cols(); j++)
1007  {
1008 // if (x(i, j) <= 0)
1009 // {
1010  Cm_nom += (1 - x(i, j))*(1 - x(i, j))*x_0(i, j);
1011  Cm_denom += (1 - x(i, j))*(1 - x(i, j));
1012 // }
1013  }
1014  }
1015 
1016  if (Cm_denom > 0)
1017  {
1018  Cm_nom /= Cm_denom;
1019  }
1020 
1021  return Cm_nom;
1022 }
1023 
1025 // Functionals::PhaseField_Color::f
1027 
1028 float Functionals::PhaseField_Color::f(const Eigen::MatrixXf &x, float epsilon)
1029 {
1030  float f_x = 0;
1031 
1032  for (int i = 0; i < x.rows(); i++)
1033  {
1034  for (int j = 0; j < x.cols(); j++)
1035  {
1036  if (i > 0)
1037  {
1038  f_x += epsilon*(x(i - 1, j) - x(i, j))*(x(i - 1, j) - x(i, j));
1039  }
1040 
1041  if (j > 0)
1042  {
1043  f_x += epsilon*(x(i, j - 1) - x(i, j))*(x(i, j - 1) - x(i, j));
1044  }
1045 
1046  f_x += (1 - x(i, j)*x(i, j))*(1 - x(i, j)*x(i, j))/epsilon;
1047  }
1048  }
1049 
1050  return f_x;
1051 }
1052 
1054 // Functionals::PhaseField_Color::df
1056 
1057 void Functionals::PhaseField_Color::df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x,
1058  float epsilon)
1059 {
1060  df_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
1061 
1062  for (int i = 0; i < x.rows(); i++)
1063  {
1064  for (int j = 0; j < x.cols(); j++)
1065  {
1066  df_x(i, j) = - 4*(1 - x(i, j)*x(i, j))*x(i, j)/epsilon;
1067 
1068  if (i > 0)
1069  {
1070  df_x(i, j) -= 2*epsilon*(x(i - 1, j) - x(i, j));
1071  }
1072 
1073  if (j > 0)
1074  {
1075  df_x(i, j) -= 2*epsilon*(x(i, j - 1) - x(i, j));
1076  }
1077 
1078  if (i < x.rows() - 1)
1079  {
1080  df_x(i, j) += 2*epsilon*(x(i, j) - x(i + 1, j));
1081  }
1082 
1083  if (j < x.cols() - 1)
1084  {
1085  df_x(i, j) += 2*epsilon*(x(i, j) - x(i, j + 1));
1086  }
1087  }
1088  }
1089 }
1090 
1092 // Functionals::PhaseField_Color::g
1094 
1095 float Functionals::PhaseField_Color::g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1096  const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda)
1097 {
1098  float g_x = 0;
1099 
1100  for (int i = 0; i < x.rows(); i++)
1101  {
1102  for (int j = 0; j < x.cols(); j++)
1103  {
1104  float cp = (x_0(i, j) - Cp(0, 0))*(x_0(i, j) - Cp(0, 0))
1105  + (x_0(x.rows() + i, j) - Cp(1, 0))*(x_0(x.rows() + i, j) - Cp(1, 0))
1106  + (x_0(2*x.rows() + i, j) - Cp(2, 0))*(x_0(2*x.rows() + i, j) - Cp(2, 0));
1107  cp = cp;
1108 
1109  float cm = (x_0(i, j) - Cm(0, 0))*(x_0(i, j) - Cm(0, 0))
1110  + (x_0(x.rows() + i, j) - Cm(1, 0))*(x_0(x.rows() + i, j) - Cm(1, 0))
1111  + (x_0(2*x.rows() + i, j) - Cm(2, 0))*(x_0(2*x.rows() + i, j) - Cm(2, 0));
1112  cm = cm;
1113 
1114  g_x += (1 + x(i, j))*(1 + x(i, j))*cp/4
1115  + (1 - x(i, j))*(1 - x(i, j))*cm/4;
1116  }
1117  }
1118 
1119  return lambda*g_x;
1120 }
1121 
1123 // Functionals::PhaseField_Color::prox_g
1125 
1126 void Functionals::PhaseField_Color::prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1127  Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda, float alpha)
1128 {
1129  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
1130 
1131  for (int i = 0; i < x.rows(); i++)
1132  {
1133  for (int j = 0; j < x.cols(); j++)
1134  {
1135  float cp = (x_0(i, j) - Cp(0, 0))*(x_0(i, j) - Cp(0, 0))
1136  + (x_0(x.rows() + i, j) - Cp(1, 0))*(x_0(x.rows() + i, j) - Cp(1, 0))
1137  + (x_0(2*x.rows() + i, j) - Cp(2, 0))*(x_0(2*x.rows() + i, j) - Cp(2, 0));
1138  cp = cp;
1139 
1140  float cm = (x_0(i, j) - Cm(0, 0))*(x_0(i, j) - Cm(0, 0))
1141  + (x_0(x.rows() + i, j) - Cm(1, 0))*(x_0(x.rows() + i, j) - Cm(1, 0))
1142  + (x_0(2*x.rows() + i, j) - Cm(2, 0))*(x_0(2*x.rows() + i, j) - Cm(2, 0));
1143  cm = cm;
1144 
1145  prox_g_x(i, j) = (x(i, j) - lambda*alpha*cp/2 + lambda*alpha*cm/2)
1146  /(1 + lambda*alpha*cp/2 + lambda*alpha*cm/2);
1147  }
1148  }
1149 }
1150 
1152 // Functionals::PhaseField::g
1154 
1155 float Functionals::PhaseField_Color::g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1156  const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda)
1157 {
1158  float g_x = 0;
1159 
1160  for (int i = 0; i < x.rows(); i++)
1161  {
1162  for (int j = 0; j < x.cols(); j++)
1163  {
1164  float cp = std::abs(x_0(i, j) - Cp(0, 0))
1165  + std::abs(x_0(x.rows() + i, j) - Cp(1, 0))
1166  + std::abs(x_0(2*x.rows() + i, j) - Cp(2, 0));
1167 
1168  float cm = std::abs(x_0(i, j) - Cm(0, 0))
1169  + std::abs(x_0(x.rows() + i, j) - Cm(1, 0))
1170  + std::abs(x_0(2*x.rows() + i, j) - Cm(2, 0));
1171 
1172  g_x += std::abs(1 + x(i, j))*cp + std::abs(1 - x(i, j))*cm;
1173  }
1174  }
1175 
1176  return lambda*g_x;
1177 }
1178 
1180 // Functionals::PhaseField::prox_g
1182 
1183 void Functionals::PhaseField_Color::prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1184  Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm,
1185  float lambda, float alpha)
1186 {
1187  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
1188 
1189  for (int i = 0; i < x.rows(); i++)
1190  {
1191  for (int j = 0; j < x.cols(); j++)
1192  {
1193  float cp = std::abs(x_0(i, j) - Cp(0, 0))
1194  + std::abs(x_0(x.rows() + i, j) - Cp(1, 0))
1195  + std::abs(x_0(2*x.rows() + i, j) - Cp(2, 0));
1196  cp *= alpha*lambda;
1197 
1198  float cm = std::abs(x_0(i, j) - Cm(0, 0))
1199  + std::abs(x_0(x.rows() + i, j) - Cm(1, 0))
1200  + std::abs(x_0(2*x.rows() + i, j) - Cm(2, 0));
1201  cm *= alpha*lambda;
1202 
1203  if (x(i, j) > 1 + (cp + cm))
1204  {
1205  prox_g_x(i, j) = -(cp + cm) + x(i, j);
1206  }
1207  else if (x(i, j) >= 1 + (cp - cm) && x(i, j) <= 1 + (cp + cm))
1208  {
1209  prox_g_x(i, j) = 1;
1210  }
1211  else if (x(i, j) > -1 + (cp - cm) && x(i, j) < 1 + (cp - cm))
1212  {
1213  prox_g_x(i, j) = (-cp + cm) + x(i, j);
1214  }
1215  else if (x(i, j) >= -1 - (cp + cm) && x(i, j) <= -1 + (cp - cm))
1216  {
1217  prox_g_x(i, j) = -1;
1218  }
1219  else
1220  {
1221  LOG_IF(FATAL, x(i, j) >= -1 - (cp + cm)) << "Invalid case in PhaseField::prox_g_absolute!";
1222  prox_g_x(i, j) = (cp + cm) + x(i, j);
1223  }
1224 
1225 // std::cout << -1 - (cp + cm) << "," << -1 + (cp - cm) << "," << 1 + (cp - cm) << "," << 1 + (cp + cm) << std::endl;
1226  }
1227  }
1228 }
1229 
1231 // Functionals::PhaseField_Color::Cp
1233 
1234 void Functionals::PhaseField_Color::Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1235  Eigen::Vector3f &Cp)
1236 {
1237  Eigen::Vector3f Cp_nom = Eigen::Vector3f::Zero();
1238  float Cp_denom = 0;
1239 
1240  for (int i = 0; i < x.rows(); i++)
1241  {
1242  for (int j = 0; j < x.cols(); j++)
1243  {
1244 // if (x(i, j) > 0)
1245 // {
1246  Cp_nom(0, 0) += (1 + x(i, j))*(1 + x(i, j))*x_0(i, j);
1247  Cp_nom(1, 0) += (1 + x(i, j))*(1 + x(i, j))*x_0(x.rows() + i, j);
1248  Cp_nom(2, 0) += (1 + x(i, j))*(1 + x(i, j))*x_0(2*x.rows() + i, j);
1249 
1250  Cp_denom += (1 + x(i, j))*(1 + x(i, j));
1251 // }
1252  }
1253  }
1254 
1255  if (Cp_denom > 0)
1256  {
1257  Cp_nom(0, 0) /= Cp_denom;
1258  Cp_nom(1, 0) /= Cp_denom;
1259  Cp_nom(2, 0) /= Cp_denom;
1260  }
1261 
1262  Cp = Cp_nom;
1263 }
1264 
1266 // Functionals::PhaseField_Color::Cm
1268 
1269 void Functionals::PhaseField_Color::Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0,
1270  Eigen::Vector3f &Cm)
1271 {
1272  Eigen::Vector3f Cm_nom = Eigen::Vector3f::Zero();
1273  float Cm_denom = 0;
1274 
1275  for (int i = 0; i < x.rows(); i++)
1276  {
1277  for (int j = 0; j < x.cols(); j++)
1278  {
1279 // if (x(i, j) <= 0)
1280 // {
1281  Cm_nom(0, 0) += (1 - x(i, j))*(1 - x(i, j))*x_0(i, j);
1282  Cm_nom(1, 0) += (1 - x(i, j))*(1 - x(i, j))*x_0(x.rows() + i, j);
1283  Cm_nom(2, 0) += (1 - x(i, j))*(1 - x(i, j))*x_0(2*x.rows() + i, j);
1284 
1285  Cm_denom += (1 - x(i, j))*(1 - x(i, j));
1286 // }
1287  }
1288  }
1289 
1290  if (Cm_denom > 0)
1291  {
1292  Cm_nom(0, 0) /= Cm_denom;
1293  Cm_nom(1, 0) /= Cm_denom;
1294  Cm_nom(2, 0) /= Cm_denom;
1295  }
1296 
1297  Cm = Cm_nom;
1298 }
1299 
1301 // Functionals::CompressiveSensing::f
1303 
1304 float Functionals::CompressiveSensing::f(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A,
1305  const Eigen::MatrixXf &y, float lambda)
1306 {
1307  Eigen::MatrixXf y_diff = A*x - y;
1308  return 1.f/lambda*0.5f*y_diff.squaredNorm();
1309 }
1310 
1312 // Functionals::CompressiveSensing::df
1314 
1315 void Functionals::CompressiveSensing::df(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A,
1316  const Eigen::MatrixXf &y, Eigen::MatrixXf &df_x, float lambda)
1317 {
1318  df_x = 1.f/lambda*((A.transpose()*A*x) - A.transpose()*y);
1319 }
1320 
1322 // Functionals::CompressiveSensing::g
1324 
1325 float Functionals::CompressiveSensing::g(const Eigen::MatrixXf &x)
1326 {
1327  return x.lpNorm<1>();
1328 }
1329 
1331 // Functionals::CompressiveSensing::prox_g
1333 
1334 void Functionals::CompressiveSensing::prox_g(const Eigen::MatrixXf &x,
1335  Eigen::MatrixXf &prox_g_x, float alpha)
1336 {
1337  prox_g_x = Eigen::MatrixXf::Zero(x.rows(), x.cols());
1338 
1339  for (int i = 0; i < x.rows(); i++)
1340  {
1341  for (int j = 0; j < x.cols(); j++)
1342  {
1343  if (x(i, j) >= alpha)
1344  {
1345  prox_g_x(i, j) = x(i, j) - alpha;
1346  }
1347  else if (std::abs(x(i, j)) < alpha)
1348  {
1349  prox_g_x(i, j) = 0;
1350  }
1351  else
1352  {
1353  prox_g_x(i, j) = x(i, j) + alpha;
1354  }
1355  }
1356  }
1357 }
1358 
1359 #endif /* FUNCTIONALS_H */
1360 
static float computePSNR(const Eigen::MatrixXf &image, const Eigen::MatrixXf &denoised_image, float range=1)
Compute PSNR to evaluate denoising applications.
Definition: functionals.h:549
static void prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda, float alpha)
Proximal map of g_absolute.
Definition: functionals.h:927
static void df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x, float epsilon)
Derivative of f.
Definition: functionals.h:823
static void df_lorentzianPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x, float sigma, float lambda)
Derivative of Lorentzian pairwise term.
Definition: functionals.h:615
static void prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda, float alpha)
Proximal map of g.
Definition: functionals.h:1126
static void Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::Vector3f &Cp)
Compute Cp from the given labels x and the image x_0.
Definition: functionals.h:1234
static float g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &X_0, float Cp, float Cm, float lambda)
Non-differentiable but convex part: |1 +- z| |x_0 + Cpm| dx.
Definition: functionals.h:904
static void addSaltPepper(const Eigen::MatrixXf &image, float p, Eigen::MatrixXf &noisy_image)
Add salt and pepper noise.
Definition: functionals.h:539
static void prox_g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_g_x, float Cp, float Cm, float lambda, float alpha)
Proximal map of g.
Definition: functionals.h:882
Two Phase-Field for color image segmentation, see [1]; adapted to color. [1] Shen. Gamma-Convergence Approximation to Piecewise Constant Mumford-Shah Segmentation. International Conference on Advanced Concepts of Intelligent Vision Systems, 2005.
Definition: functionals.h:303
static void Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::Vector3f &Cm)
Compute Cp::m from the given labels x and the image x_0.
Definition: functionals.h:1269
static void addGaussianAdditive(const Eigen::MatrixXf &image, float sigma, Eigen::MatrixXf &noisy_image)
Add additive Gaussian noise.
Definition: functionals.h:518
static void convertEigenToOpenCV(const Eigen::MatrixXf &eigen, cv::Mat &opencv)
Convert Eigen matrix to OpenCV matrix.
Definition: functionals.h:438
static void df(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x, float epsilon)
Derivative of f.
Definition: functionals.h:1057
static float f_squaredPairwise(const Eigen::MatrixXf &x, float lambda)
Squared pairwise term.
Definition: functionals.h:651
Denoising functionals (for grayscale images!.
Definition: functionals.h:89
static float g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda)
Non-differentiable but convex part: (1 +- z)^2/4 (x_0 + Cpm)^2 dx.
Definition: functionals.h:1095
Utilities for using nmiPiano/iPiano for computer vision/image processing.
Definition: functionals.h:59
static float f(const Eigen::MatrixXf &x, float epsilon)
Differentiable but non-convex part: 9 | z|^2 + (1-z^2)^2/(64) dx.
Definition: functionals.h:1028
Generate noisy images.
Definition: functionals.h:94
static float g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
Squared unary, i.e. data, term.
Definition: functionals.h:757
static void df_smoothAbsolutePairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x, float epsilon, float lambda)
Derivative of smooth absolute pairwise term.
static void convertEigenToOpenCV_Color(const Eigen::MatrixXf &eigen, cv::Mat &opencv)
Convert Eigen matrix to OpenCV color matrix.
Definition: functionals.h:475
static float f(const Eigen::MatrixXf &x, float epsilon)
Differentiable but non-convex part: 9 | z|^2 + (1-z^2)^2/(64) dx.
Definition: functionals.h:794
static float Cm(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
Compute Cp::m from the given labels x and the image x_0.
Definition: functionals.h:999
A collection of functionals for different computer vision/image processing tasks used to demonstrate ...
Definition: functionals.h:54
Two Phase-Field for segmentation, see [1]. [1] Shen. Gamma-Convergence Approximation to Piecewise Con...
Definition: functionals.h:217
static float g(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, float Cp, float Cm, float lambda)
Non-differentiable but convex part: (1 +- z)^2/4 (x_0 + Cpm)^2 dx.
Definition: functionals.h:861
static float g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &X_0, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda)
Non-differentiable but convex part: |1 +- z| |x_0 + Cpm| dx.
Definition: functionals.h:1155
static void convertOpenCVToEigen(const cv::Mat &opencv, Eigen::MatrixXf &eigen)
Convert OpenCV matrix to Eigen matrix.
Definition: functionals.h:455
static float g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
Absolute unary, i.e. data, term.
Definition: functionals.h:714
Evaluation of denoising functionals.
Definition: functionals.h:116
static void prox_g_squaredUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_f_x, float alpha)
Proximal map of squared unary term.
Definition: functionals.h:776
static float g(const Eigen::MatrixXf &x)
Non-differentiable but convex part: |x|_1.
Definition: functionals.h:1325
static void df(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A, const Eigen::MatrixXf &y, Eigen::MatrixXf &df_x, float lambda)
Derivative of f.
Definition: functionals.h:1315
static void df_squaredPairwise(const Eigen::MatrixXf &x, Eigen::MatrixXf &df_x, float lambda)
Derivative of squared pairwise term.
Definition: functionals.h:678
static void convertOpenCVToEigen_Color(const cv::Mat &opencv, Eigen::MatrixXf &eigen)
Convert OpenCV color matrix to Eigen matrix.
Definition: functionals.h:496
static void prox_g_absolute(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_g_x, const Eigen::Vector3f &Cp, const Eigen::Vector3f &Cm, float lambda, float alpha)
Proximal map of g_absolute.
Definition: functionals.h:1183
static void prox_g(const Eigen::MatrixXf &x, Eigen::MatrixXf &prox_g_x, float alpha)
Proximal map of g.
Definition: functionals.h:1334
static float f(const Eigen::MatrixXf &x, const Eigen::MatrixXf &A, const Eigen::MatrixXf &y, float lambda)
Differentiable but non-convex part: |Ax - y|_2^2.
Definition: functionals.h:1304
Compressive sensing example using convex optimization as discussed in [1]: [1] G. Kutyniok...
Definition: functionals.h:391
static void prox_g_absoluteUnary(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0, Eigen::MatrixXf &prox_f_x, float alpha)
Proximal map of absolute unary term.
Definition: functionals.h:739
static float f_lorentzianPairwise(const Eigen::MatrixXf &x, float sigma, float lambda)
Lorentzian pairwise term.
Definition: functionals.h:583
static float f_smoothAbsolutePairwise(const Eigen::MatrixXf &x, float epsilon, float lambda)
Smooth absolute pairwise term.
static float Cp(const Eigen::MatrixXf &x, const Eigen::MatrixXf &x_0)
Compute Cp from the given labels x and the image x_0.
Definition: functionals.h:970