Advertisement
Guest User

Untitled

a guest
May 23rd, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.77 KB | None | 0 0
  1. #include "stdint.h"
  2. #include "math.h"
  3.  
  4. #include <memory>
  5. #include <algorithm>
  6.  
  7. #define ELEMENT_AT( ARRAY, ROW, COLUMN ) ARRAY[( ROW ) * ( width ) + ( COLUMN )]
  8.  
  9. const double numerator      = 255.;
  10. const double denonimator    = 1. / 255.;
  11. const double sqrt2          = 1.41421356237;
  12.  
  13. void createImageDoubleArray( const uint8_t* const img, int width, int height, double* outImage )
  14. {
  15.     for ( int i = 0, size = width * height; i < size; ++i )
  16.     {
  17.         if ( img[i] == 255 )
  18.             outImage[i] = 1.;
  19.         else
  20.         {
  21.             if ( img[i] == 0 )
  22.                 outImage[i] = 0.;
  23.             else
  24.                 outImage[i] = static_cast<double>( img[i] ) * denonimator;
  25.         }
  26.     }
  27. }
  28.  
  29. void createImageUintArray( const double* const img, int width, int height, uint8_t* outImage )
  30. {
  31.     for ( int i = 0, size = width * height; i < size; ++i )
  32.     {
  33.         if ( img[i] == 1. )
  34.             outImage[i] = 255;
  35.         else
  36.         {
  37.             if ( img[i] == 0. )
  38.                 outImage[i] = 0;
  39.             else
  40.                 outImage[i] = static_cast<uint8_t>( static_cast<double>( img[i] ) * numerator );
  41.         }
  42.     }
  43. }
  44.  
  45. void calculateImageGradient( const double* const img, int width, int height, double* outGradientX, double* outGradientY )
  46. {
  47.     for ( int rowIndex = 1; rowIndex < height - 1; ++rowIndex )
  48.     {
  49.         for ( int columnIndex = 1; columnIndex < width - 1; ++columnIndex )
  50.         {
  51.             // Вычисляем градиент только в местах контура ( где должно соблюдаться сглаживание )
  52.             if ( 0.0 < ELEMENT_AT( img, rowIndex, columnIndex ) && ELEMENT_AT( img, rowIndex, columnIndex) < 1.0 )
  53.             {
  54.                 ELEMENT_AT( outGradientX, rowIndex, columnIndex ) = -ELEMENT_AT( img, rowIndex - 1, columnIndex - 1 ) - sqrt2 *
  55.                                                                      ELEMENT_AT( img, rowIndex    , columnIndex - 1 ) -
  56.                                                                      ELEMENT_AT( img, rowIndex + 1, columnIndex - 1 ) +
  57.                                                                      ELEMENT_AT( img, rowIndex - 1, columnIndex + 1 ) + sqrt2 *
  58.                                                                      ELEMENT_AT( img, rowIndex    , columnIndex + 1 ) +
  59.                                                                      ELEMENT_AT( img, rowIndex + 1, columnIndex + 1 ) ;
  60.  
  61.                 ELEMENT_AT( outGradientY, rowIndex, columnIndex ) = -ELEMENT_AT( img, rowIndex - 1, columnIndex - 1 ) - sqrt2 *
  62.                                                                      ELEMENT_AT( img, rowIndex - 1, columnIndex     ) -
  63.                                                                      ELEMENT_AT( img, rowIndex - 1, columnIndex + 1 ) +
  64.                                                                      ELEMENT_AT( img, rowIndex + 1, columnIndex - 1 ) + sqrt2 *
  65.                                                                      ELEMENT_AT( img, rowIndex + 1, columnIndex     ) +
  66.                                                                      ELEMENT_AT( img, rowIndex + 1, columnIndex + 1 ) ;
  67.  
  68.                 const double length2 = ELEMENT_AT( outGradientX, rowIndex, columnIndex ) * ELEMENT_AT( outGradientX, rowIndex, columnIndex ) +
  69.                                        ELEMENT_AT( outGradientY, rowIndex, columnIndex ) * ELEMENT_AT( outGradientY, rowIndex, columnIndex );
  70.  
  71.                 // Процесс нормализации
  72.                 if ( length2 > 0.0 )
  73.                 {
  74.                     const double lengthInverse = 1.0 / sqrt( length2 );
  75.  
  76.                     ELEMENT_AT( outGradientX, rowIndex, columnIndex ) *= lengthInverse;
  77.                     ELEMENT_AT( outGradientY, rowIndex, columnIndex ) *= lengthInverse;
  78.                 }
  79.             }
  80.         }
  81.     }
  82. }
  83.  
  84. double calculateEdgeDistanceFunction( double gradientX, double gradientY, double a )
  85. {
  86.     if ( ( gradientX < 1e-12 ) || ( gradientY < 1e-12 ) )
  87.         return 0.5 - a;
  88.     else
  89.     {
  90.         gradientX = fabs( gradientX );
  91.         gradientY = fabs( gradientY );
  92.  
  93.         if ( gradientX < gradientY )
  94.             std::swap( gradientX, gradientY );
  95.  
  96.         const double a1 = 0.5 * gradientY / gradientX;
  97.  
  98.         // 0 <= a < a1
  99.         if ( a < a1 )
  100.             return 0.5 * ( gradientX + gradientY ) - sqrt( 2.0 * gradientX * gradientY * a );
  101.         else
  102.         {
  103.             // a1 <= a <= 1 - a1
  104.             if ( a < ( 1.0 - a1 ) )
  105.                 return ( 0.5 - a ) * gradientX;
  106.             else
  107.                 return -0.5 * ( gradientX + gradientY ) + sqrt( 2.0 * gradientX * gradientY * ( 1.0 - a ) );
  108.         }
  109.     }    
  110. }
  111.  
  112. double calculatDistanceAA( double imageValue, double gradientX, double gradientY, double dx, double dy )
  113. {
  114.     if ( imageValue < 1e-12 )
  115.         return 1e9;
  116.  
  117.     const double di = sqrt( dx * dx + dy * dy );
  118.  
  119.     if ( di < 1e-12 )
  120.         return di + calculateEdgeDistanceFunction( gradientX, gradientY, imageValue );
  121.     else
  122.         return di + calculateEdgeDistanceFunction( dx, dy, imageValue );
  123. }
  124.  
  125. #define EQUATE_VALUES()                                             \
  126.                     {                                               \
  127.                         distanceX[index]        = newDistanceX;     \
  128.                         distanceY[index]        = newDistanceY;     \
  129.                         outDistanceImage[index] = newDistanceImage; \
  130.                         oldDistance             = newDistanceImage; \
  131.                         isChanged               = true;             \
  132.                     }                                               \
  133.  
  134. void startFilter( const double* const img, const double* const gradientX, const double* const gradientY, int width, int height, double* outDistanceImage )
  135. {
  136.     const int size = width * height;
  137.  
  138.     auto distanceX = std::make_unique<int[]>( size );
  139.     auto distanceY = std::make_unique<int[]>( size );
  140.  
  141.     for ( int i = 0; i < size; ++i )
  142.     {
  143.         distanceX[i] = 0;
  144.         distanceX[i] = 0;
  145.  
  146.         if ( img[i] <= 0.0 )
  147.             outDistanceImage[i] = 1e9;
  148.         else
  149.         {
  150.             if ( img[i] < 1.0 )
  151.                 outDistanceImage[i] = calculateEdgeDistanceFunction( gradientX[i], gradientY[i], img[i] );
  152.             else
  153.                 outDistanceImage[i] = 0.0;
  154.         }
  155.     }
  156.  
  157.     const int offset_u  = -width;
  158.     const int offset_ur = -width + 1;
  159.     const int offset_r  = +1;
  160.     const int offset_rd = +width + 1;
  161.     const int offset_d  = +width;
  162.     const int offset_dl = +width - 1;
  163.     const int offset_l  = -1;
  164.     const int offset_lu = -width - 1;
  165.  
  166.     for ( bool isChanged = false; ; isChanged = false )
  167.     {
  168.         for ( int row = 1; row < height; ++row )
  169.         {
  170.             int     index       = row * width;
  171.  
  172.             double  oldDistance = outDistanceImage[index];
  173.  
  174.             if ( oldDistance > 0.0 )
  175.             {
  176.                 {
  177.                     const int c = index + offset_u;
  178.  
  179.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  180.  
  181.                     const int newDistanceX = distanceX[c];
  182.                     const int newDistanceY = distanceY[c] + 1;
  183.  
  184.                     const double newDistanceImage =
  185.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  186.  
  187.                     if ( newDistanceImage < oldDistance - 1e-6 )
  188.                         EQUATE_VALUES();
  189.                 }
  190.  
  191.                 {
  192.                     const int c = index + offset_ur;
  193.  
  194.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  195.  
  196.                     const int newDistanceX = distanceX[c] - 1;
  197.                     const int newDistanceY = distanceY[c] + 1;
  198.  
  199.                     const double newDistanceImage =
  200.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  201.  
  202.                     if ( newDistanceImage < oldDistance - 1e-6 )
  203.                         EQUATE_VALUES();
  204.                 }
  205.             }
  206.  
  207.             ++index;
  208.  
  209.             for ( int column = 1; column < width - 1; ++column, ++index )
  210.             {
  211.                 oldDistance = outDistanceImage[index];
  212.  
  213.                 if ( oldDistance <= 1e-12 )
  214.                     continue;
  215.  
  216.                 {
  217.                     const int c = index + offset_l;
  218.  
  219.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  220.  
  221.                     const int newDistanceX = distanceX[c] + 1;
  222.                     const int newDistanceY = distanceY[c];
  223.  
  224.                     const double newDistanceImage =
  225.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  226.  
  227.                     if ( newDistanceImage < oldDistance - 1e-6 )
  228.                         EQUATE_VALUES();
  229.                 }
  230.  
  231.                 {
  232.                     const int c = index + offset_lu;
  233.  
  234.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  235.  
  236.                     const int newDistanceX = distanceX[c] + 1;
  237.                     const int newDistanceY = distanceY[c] + 1;
  238.  
  239.                     const double newDistanceImage =
  240.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  241.  
  242.                     if ( newDistanceImage < oldDistance - 1e-6 )
  243.                         EQUATE_VALUES();
  244.                 }
  245.  
  246.                 {
  247.                     const int c = index + offset_u;
  248.  
  249.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  250.  
  251.                     const int newDistanceX = distanceX[c];
  252.                     const int newDistanceY = distanceY[c] + 1;
  253.  
  254.                     const double newDistanceImage =
  255.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  256.  
  257.                     if ( newDistanceImage < oldDistance - 1e-6 )
  258.                         EQUATE_VALUES();
  259.                 }
  260.  
  261.                 {
  262.                     const int c = index + offset_ur;
  263.  
  264.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  265.  
  266.                     const int newDistanceX = distanceX[c] - 1;
  267.                     const int newDistanceY = distanceY[c] + 1;
  268.  
  269.                     const double newDistanceImage =
  270.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  271.  
  272.                     if ( newDistanceImage < oldDistance - 1e-6 )
  273.                         EQUATE_VALUES();
  274.                 }
  275.             } // end for
  276.  
  277.             oldDistance = outDistanceImage[index];
  278.  
  279.             if ( oldDistance > 0.0 )
  280.             {
  281.                 {
  282.                     const int c = index + offset_l;
  283.  
  284.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  285.  
  286.                     const int newDistanceX = distanceX[c] + 1;
  287.                     const int newDistanceY = distanceY[c];
  288.  
  289.                     const double newDistanceImage =
  290.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  291.  
  292.                     if ( newDistanceImage < oldDistance - 1e-6 )
  293.                         EQUATE_VALUES();
  294.                 }
  295.  
  296.                 {
  297.                     const int c = index + offset_lu;
  298.  
  299.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  300.  
  301.                     const int newDistanceX = distanceX[c] + 1;
  302.                     const int newDistanceY = distanceY[c] + 1;
  303.  
  304.                     const double newDistanceImage =
  305.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  306.  
  307.                     if ( newDistanceImage < oldDistance - 1e-6 )
  308.                         EQUATE_VALUES();
  309.                 }
  310.  
  311.                 {
  312.                     const int c = index + offset_u;
  313.  
  314.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  315.  
  316.                     const int newDistanceX = distanceX[c];
  317.                     const int newDistanceY = distanceY[c] + 1;
  318.  
  319.                     const double newDistanceImage =
  320.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  321.  
  322.                     if ( newDistanceImage < oldDistance - 1e-6 )
  323.                         EQUATE_VALUES();
  324.                 }
  325.             } // end if
  326.  
  327.             index = ( row + 1 ) * width - 2;
  328.  
  329.             for ( int column = width - 2; column >= 0; --column, --index )
  330.             {
  331.                 oldDistance = outDistanceImage[index];
  332.  
  333.                 if ( oldDistance <= 1e-12 )
  334.                     continue;
  335.  
  336.                 {
  337.                     const int c = index + offset_r;
  338.  
  339.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  340.  
  341.                     const int newDistanceX = distanceX[c] - 1;
  342.                     const int newDistanceY = distanceY[c];
  343.  
  344.                     const double newDistanceImage =
  345.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  346.  
  347.                     if ( newDistanceImage < oldDistance - 1e-6 )
  348.                         EQUATE_VALUES();
  349.                 }
  350.             }
  351.         } // end row for
  352.  
  353.         for ( int row = height - 2;  row >= 0; --row )
  354.         {
  355.             int     index       = ( row + 1 ) * width - 1;
  356.             double  oldDistance = outDistanceImage[index];
  357.  
  358.             if ( oldDistance > 0.0 )
  359.             {
  360.                 {
  361.                     const int c = index + offset_d;
  362.  
  363.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  364.  
  365.                     const int newDistanceX = distanceX[c];
  366.                     const int newDistanceY = distanceY[c] - 1;
  367.  
  368.                     const double newDistanceImage =
  369.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  370.  
  371.                     if ( newDistanceImage < oldDistance - 1e-6 )
  372.                         EQUATE_VALUES();
  373.                 }
  374.  
  375.                 {
  376.                     const int c = index + offset_dl;
  377.  
  378.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  379.  
  380.                     const int newDistanceX = distanceX[c] + 1;
  381.                     const int newDistanceY = distanceY[c] - 1;
  382.  
  383.                     const double newDistanceImage =
  384.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  385.  
  386.                     if ( newDistanceImage < oldDistance - 1e-6 )
  387.                         EQUATE_VALUES();
  388.                 }
  389.             } // end if
  390.  
  391.             --index;
  392.  
  393.             for ( int column = width - 2; width > 0; --column, --index )
  394.             {
  395.                 oldDistance = outDistanceImage[index];
  396.  
  397.                 if ( oldDistance <= 1e-12 )
  398.                     continue;
  399.  
  400.                 {
  401.                     const int c = index + offset_r;
  402.  
  403.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  404.  
  405.                     const int newDistanceX = distanceX[c] - 1;
  406.                     const int newDistanceY = distanceY[c];
  407.  
  408.                     const double newDistanceImage =
  409.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  410.  
  411.                     if ( newDistanceImage < oldDistance - 1e-6 )
  412.                         EQUATE_VALUES();
  413.                 }
  414.  
  415.                 {
  416.                     const int c = index + offset_rd;
  417.  
  418.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  419.  
  420.                     const int newDistanceX = distanceX[c] - 1;
  421.                     const int newDistanceY = distanceY[c] - 1;
  422.  
  423.                     const double newDistanceImage =
  424.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  425.  
  426.                     if ( newDistanceImage < oldDistance - 1e-6 )
  427.                         EQUATE_VALUES();
  428.                 }
  429.  
  430.                 {
  431.                     const int c = index + offset_d;
  432.  
  433.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  434.  
  435.                     const int newDistanceX = distanceX[c];
  436.                     const int newDistanceY = distanceY[c] - 1;
  437.  
  438.                     const double newDistanceImage =
  439.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  440.  
  441.                     if ( newDistanceImage < oldDistance - 1e-6 )
  442.                         EQUATE_VALUES();
  443.                 }
  444.  
  445.                 {
  446.                     const int c = index + offset_dl;
  447.  
  448.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  449.  
  450.                     const int newDistanceX = distanceX[c] + 1;
  451.                     const int newDistanceY = distanceY[c] - 1;
  452.  
  453.                     const double newDistanceImage =
  454.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  455.  
  456.                     if ( newDistanceImage < oldDistance - 1e-6 )
  457.                         EQUATE_VALUES();
  458.                 }
  459.             } // end for
  460.  
  461.             oldDistance = outDistanceImage[index];
  462.  
  463.             if ( oldDistance > 0.0 )
  464.             {
  465.                 {
  466.                     const int c = index + offset_r;
  467.  
  468.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  469.  
  470.                     const int newDistanceX = distanceX[c] - 1;
  471.                     const int newDistanceY = distanceY[c];
  472.  
  473.                     const double newDistanceImage =
  474.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  475.  
  476.                     if ( newDistanceImage < oldDistance - 1e-6 )
  477.                         EQUATE_VALUES();
  478.                 }
  479.  
  480.                 {
  481.                     const int c = index + offset_rd;
  482.  
  483.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  484.  
  485.                     const int newDistanceX = distanceX[c] - 1;
  486.                     const int newDistanceY = distanceY[c] - 1;
  487.  
  488.                     const double newDistanceImage =
  489.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  490.  
  491.                     if ( newDistanceImage < oldDistance - 1e-6 )
  492.                         EQUATE_VALUES();
  493.                 }
  494.  
  495.                 {
  496.                     const int c = index + offset_d;
  497.  
  498.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  499.  
  500.                     const int newDistanceX = distanceX[c];
  501.                     const int newDistanceY = distanceY[c] - 1;
  502.  
  503.                     const double newDistanceImage =
  504.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  505.  
  506.                     if ( newDistanceImage < oldDistance - 1e-6 )
  507.                         EQUATE_VALUES();
  508.                 }
  509.             } // end if
  510.  
  511.             index = row * width + 1;
  512.  
  513.             for ( int column = 1; column < width; ++column, ++index )
  514.             {
  515.                 oldDistance = outDistanceImage[index];
  516.  
  517.                 if ( oldDistance <= 1e-12 )
  518.                     continue;
  519.  
  520.                 {
  521.                     const int c = index + offset_l;
  522.  
  523.                     const int closestIndex = c - distanceX[c] - distanceY[c] * width;
  524.  
  525.                     const int newDistanceX = distanceX[c] + 1;
  526.                     const int newDistanceY = distanceY[c];
  527.  
  528.                     const double newDistanceImage =
  529.                         calculatDistanceAA( img[closestIndex], gradientX[closestIndex], gradientY[closestIndex], newDistanceX, newDistanceY);
  530.  
  531.                     if ( newDistanceImage < oldDistance - 1e-6 )
  532.                         EQUATE_VALUES();
  533.                 }
  534.             }
  535.         }
  536.  
  537.         if ( !isChanged )
  538.             return;
  539.     }
  540. }
  541.  
  542. void createSDF( const uint8_t* const img, int width, int height, uint8_t* outImage)
  543. {
  544.     const int size = width * height;
  545.  
  546.     std::unique_ptr<double[]> doubleGrayScaleImage = std::make_unique<double[]>( size );
  547.     createImageDoubleArray( img, width, height, doubleGrayScaleImage.get() );
  548.  
  549.     std::unique_ptr<double[]> dgradientX = std::make_unique<double[]>( size );
  550.     std::unique_ptr<double[]> dgradientY = std::make_unique<double[]>( size );
  551.  
  552.     calculateImageGradient( doubleGrayScaleImage.get(), width, height, dgradientX.get(), dgradientY.get() );
  553.  
  554.     std::unique_ptr<double[]> doubleOutImage = std::make_unique<double[]>( size );
  555.     startFilter( doubleGrayScaleImage.get(), dgradientX.get(), dgradientY.get(), width, height, doubleOutImage.get() );
  556.  
  557.     createImageUintArray( doubleOutImage.get(), width, height, outImage );
  558. }
  559.  
  560. int main()
  561. {
  562.     // TEST( testSDFGenerator() );
  563. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement