Finding arrays of pixels perpendicular to a derivative












1












$begingroup$


I have a question that I originally posted to Stackoverflow, but got no answers, and was encouraged to re-post here. I am developing a method for “straightening” binary-masks of pictures of carrot roots. I have traced midlines through the masks. For example, I start with a binary mask:



binary-mask



I then use Voronoi diagrams to estimate the midline, as shown in red:



binary-mask with midline



I would now like to find the length of the “slices” that run perpendicular to the midline at each point, which would then constitute the appropriate width of the root at any given point along its length. I am using a method similar to that explained here to find the derivative of the fitted spline connecting points along the midline:



def get_spline_derivative(points):

x_max = points[:, 0].max()
# x_min = points[:, 0].min()
new_length = x_max

x = points[:, 0]
y = points[:, 1]

# new_x = np.linspace(x_min, x_max, new_length)

# new_x = np.linspace(0, 1, 2000) # this is the one that works
new_x = np.linspace(0, 1, new_length) # this is the one that works

tck, u = itp.splprep([x, y])
dx, dy = itp.splev(new_x, tck, der=1)

return list(zip(dx, dy))


This produces an enormous array, shortened here (full output here):



[(-559.8864500362733, -105.4032498463578), (-560.2848158832071, -109.774387868758), (-560.6711489905051, -113.82253391400316), (-561.0454493581669, -117.54768798209324), (-561.4077169861929, -120.94985007302827), ..., (-533.1106034956821, 74.87936144117594)]



I am unsure how to then use this output to find the vector perpendicular to this derivative, and then calculate the length of the “bin” of pixels that is within the polygon, running along this vector.



Does anyone have experience with performing this computations using Python?










share|cite|improve this question









$endgroup$

















    1












    $begingroup$


    I have a question that I originally posted to Stackoverflow, but got no answers, and was encouraged to re-post here. I am developing a method for “straightening” binary-masks of pictures of carrot roots. I have traced midlines through the masks. For example, I start with a binary mask:



    binary-mask



    I then use Voronoi diagrams to estimate the midline, as shown in red:



    binary-mask with midline



    I would now like to find the length of the “slices” that run perpendicular to the midline at each point, which would then constitute the appropriate width of the root at any given point along its length. I am using a method similar to that explained here to find the derivative of the fitted spline connecting points along the midline:



    def get_spline_derivative(points):

    x_max = points[:, 0].max()
    # x_min = points[:, 0].min()
    new_length = x_max

    x = points[:, 0]
    y = points[:, 1]

    # new_x = np.linspace(x_min, x_max, new_length)

    # new_x = np.linspace(0, 1, 2000) # this is the one that works
    new_x = np.linspace(0, 1, new_length) # this is the one that works

    tck, u = itp.splprep([x, y])
    dx, dy = itp.splev(new_x, tck, der=1)

    return list(zip(dx, dy))


    This produces an enormous array, shortened here (full output here):



    [(-559.8864500362733, -105.4032498463578), (-560.2848158832071, -109.774387868758), (-560.6711489905051, -113.82253391400316), (-561.0454493581669, -117.54768798209324), (-561.4077169861929, -120.94985007302827), ..., (-533.1106034956821, 74.87936144117594)]



    I am unsure how to then use this output to find the vector perpendicular to this derivative, and then calculate the length of the “bin” of pixels that is within the polygon, running along this vector.



    Does anyone have experience with performing this computations using Python?










    share|cite|improve this question









    $endgroup$















      1












      1








      1





      $begingroup$


      I have a question that I originally posted to Stackoverflow, but got no answers, and was encouraged to re-post here. I am developing a method for “straightening” binary-masks of pictures of carrot roots. I have traced midlines through the masks. For example, I start with a binary mask:



      binary-mask



      I then use Voronoi diagrams to estimate the midline, as shown in red:



      binary-mask with midline



      I would now like to find the length of the “slices” that run perpendicular to the midline at each point, which would then constitute the appropriate width of the root at any given point along its length. I am using a method similar to that explained here to find the derivative of the fitted spline connecting points along the midline:



      def get_spline_derivative(points):

      x_max = points[:, 0].max()
      # x_min = points[:, 0].min()
      new_length = x_max

      x = points[:, 0]
      y = points[:, 1]

      # new_x = np.linspace(x_min, x_max, new_length)

      # new_x = np.linspace(0, 1, 2000) # this is the one that works
      new_x = np.linspace(0, 1, new_length) # this is the one that works

      tck, u = itp.splprep([x, y])
      dx, dy = itp.splev(new_x, tck, der=1)

      return list(zip(dx, dy))


      This produces an enormous array, shortened here (full output here):



      [(-559.8864500362733, -105.4032498463578), (-560.2848158832071, -109.774387868758), (-560.6711489905051, -113.82253391400316), (-561.0454493581669, -117.54768798209324), (-561.4077169861929, -120.94985007302827), ..., (-533.1106034956821, 74.87936144117594)]



      I am unsure how to then use this output to find the vector perpendicular to this derivative, and then calculate the length of the “bin” of pixels that is within the polygon, running along this vector.



      Does anyone have experience with performing this computations using Python?










      share|cite|improve this question









      $endgroup$




      I have a question that I originally posted to Stackoverflow, but got no answers, and was encouraged to re-post here. I am developing a method for “straightening” binary-masks of pictures of carrot roots. I have traced midlines through the masks. For example, I start with a binary mask:



      binary-mask



      I then use Voronoi diagrams to estimate the midline, as shown in red:



      binary-mask with midline



      I would now like to find the length of the “slices” that run perpendicular to the midline at each point, which would then constitute the appropriate width of the root at any given point along its length. I am using a method similar to that explained here to find the derivative of the fitted spline connecting points along the midline:



      def get_spline_derivative(points):

      x_max = points[:, 0].max()
      # x_min = points[:, 0].min()
      new_length = x_max

      x = points[:, 0]
      y = points[:, 1]

      # new_x = np.linspace(x_min, x_max, new_length)

      # new_x = np.linspace(0, 1, 2000) # this is the one that works
      new_x = np.linspace(0, 1, new_length) # this is the one that works

      tck, u = itp.splprep([x, y])
      dx, dy = itp.splev(new_x, tck, der=1)

      return list(zip(dx, dy))


      This produces an enormous array, shortened here (full output here):



      [(-559.8864500362733, -105.4032498463578), (-560.2848158832071, -109.774387868758), (-560.6711489905051, -113.82253391400316), (-561.0454493581669, -117.54768798209324), (-561.4077169861929, -120.94985007302827), ..., (-533.1106034956821, 74.87936144117594)]



      I am unsure how to then use this output to find the vector perpendicular to this derivative, and then calculate the length of the “bin” of pixels that is within the polygon, running along this vector.



      Does anyone have experience with performing this computations using Python?







      calculus linear-algebra tangent-line image-processing python






      share|cite|improve this question













      share|cite|improve this question











      share|cite|improve this question




      share|cite|improve this question










      asked Dec 19 '18 at 2:48









      Scott B.Scott B.

      61




      61






















          1 Answer
          1






          active

          oldest

          votes


















          0












          $begingroup$

          I think the two big steps are 1. finding the perpendicular lines to the midline, and 2. finding the distance to the edge along these lines.



          The first task is relatively straightforward. Suppose the midline is defined by the points $(x_1,y_1), (x_2,y_2), ldots, (x_k,y_k)$. You can find the tangent vector $(Delta x,Delta y) = (x_2-x_1,y_2-y_1)$ at a point $(x_1,y_1)$, and then find the vector orthogonal to this: $ (-Delta y, Delta x) $ and normalize it.



          Now, note that you will get $k-1$ perpendicular lines. So instead of using the original data for the midline, it would probably make sense to smooth it (using some spline interpolation) and then sample the spline to get one more point than the number of perpendicular lines you want.



          The second task is a bit tricker. It looks like the carrot shape is more or less convex which means you could essentially define the boundary as a bunch of hyperplanes, and then see where the line from task 1 intersects them. I'm sure there are libraries for this, and if you search "intersect line with convex shape" there are lots of results.



          Another thought is to find the points on the boundary such that the slope between the point on the midline and the boundary point is as close to possible as the slope of the normal at the point on the midline. Once you have those points, you can then compute the distance to them from the midline point.



          If speed is a concern, searching for these points can probably be done using some kind of bisection.



          Sample code



          enter image description here



          We store the boudary points in an array of points called boundary (black points) and the midline in an array of points called midline (red points). The following code identifies the two blue points which approximate the intersection of the normal line (in grey) with the boundary.



          The first task is to find the unit tangent at a point. We can do this for all points simultaneously:



          slopes = midline[1:] - midline[:-1]
          tangents = [1,-1]*slopes[:,::-1]
          tangents /= np.linalg.norm(tangents,axis=1)[:,None]


          Now suppose you have a known point p on and a known direction n.
          We first compute the direction from p to each boundary point.



          vec_to_boundary = (boundary - p)
          vec_to_boundary /= np.linalg.norm(slope_to_boundary,axis=1)[:,None]


          Now compute the inner product with each of these vectors.



          inner_product_normal = slope_to_boundary@n



          The largest (in magnitude) inner products will tell us which points on the boundary are closest to the normal line passing through p.



          b0 = np.argmax(inner_product_normal)
          b1 = np.argmin(inner_product_normal)


          Finally, we can approximate the distance to the boundary from p along n as the distance to the boundary points we found.



          d1 = np.linalg.norm(boundary[b0] - p)
          d2 = np.linalg.norm(boundary[b1] - p)


          Note that for this to work well you need that the boundary have enough points that the stored boundary points are "close" to the intersection of the normal line with the "true" boundary. It also assumes the boundary is convex. In practice you will probably have to smooth the midline and boundary before using this type of approach.






          share|cite|improve this answer











          $endgroup$














            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "69"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            noCode: true, onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmath.stackexchange.com%2fquestions%2f3045932%2ffinding-arrays-of-pixels-perpendicular-to-a-derivative%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0












            $begingroup$

            I think the two big steps are 1. finding the perpendicular lines to the midline, and 2. finding the distance to the edge along these lines.



            The first task is relatively straightforward. Suppose the midline is defined by the points $(x_1,y_1), (x_2,y_2), ldots, (x_k,y_k)$. You can find the tangent vector $(Delta x,Delta y) = (x_2-x_1,y_2-y_1)$ at a point $(x_1,y_1)$, and then find the vector orthogonal to this: $ (-Delta y, Delta x) $ and normalize it.



            Now, note that you will get $k-1$ perpendicular lines. So instead of using the original data for the midline, it would probably make sense to smooth it (using some spline interpolation) and then sample the spline to get one more point than the number of perpendicular lines you want.



            The second task is a bit tricker. It looks like the carrot shape is more or less convex which means you could essentially define the boundary as a bunch of hyperplanes, and then see where the line from task 1 intersects them. I'm sure there are libraries for this, and if you search "intersect line with convex shape" there are lots of results.



            Another thought is to find the points on the boundary such that the slope between the point on the midline and the boundary point is as close to possible as the slope of the normal at the point on the midline. Once you have those points, you can then compute the distance to them from the midline point.



            If speed is a concern, searching for these points can probably be done using some kind of bisection.



            Sample code



            enter image description here



            We store the boudary points in an array of points called boundary (black points) and the midline in an array of points called midline (red points). The following code identifies the two blue points which approximate the intersection of the normal line (in grey) with the boundary.



            The first task is to find the unit tangent at a point. We can do this for all points simultaneously:



            slopes = midline[1:] - midline[:-1]
            tangents = [1,-1]*slopes[:,::-1]
            tangents /= np.linalg.norm(tangents,axis=1)[:,None]


            Now suppose you have a known point p on and a known direction n.
            We first compute the direction from p to each boundary point.



            vec_to_boundary = (boundary - p)
            vec_to_boundary /= np.linalg.norm(slope_to_boundary,axis=1)[:,None]


            Now compute the inner product with each of these vectors.



            inner_product_normal = slope_to_boundary@n



            The largest (in magnitude) inner products will tell us which points on the boundary are closest to the normal line passing through p.



            b0 = np.argmax(inner_product_normal)
            b1 = np.argmin(inner_product_normal)


            Finally, we can approximate the distance to the boundary from p along n as the distance to the boundary points we found.



            d1 = np.linalg.norm(boundary[b0] - p)
            d2 = np.linalg.norm(boundary[b1] - p)


            Note that for this to work well you need that the boundary have enough points that the stored boundary points are "close" to the intersection of the normal line with the "true" boundary. It also assumes the boundary is convex. In practice you will probably have to smooth the midline and boundary before using this type of approach.






            share|cite|improve this answer











            $endgroup$


















              0












              $begingroup$

              I think the two big steps are 1. finding the perpendicular lines to the midline, and 2. finding the distance to the edge along these lines.



              The first task is relatively straightforward. Suppose the midline is defined by the points $(x_1,y_1), (x_2,y_2), ldots, (x_k,y_k)$. You can find the tangent vector $(Delta x,Delta y) = (x_2-x_1,y_2-y_1)$ at a point $(x_1,y_1)$, and then find the vector orthogonal to this: $ (-Delta y, Delta x) $ and normalize it.



              Now, note that you will get $k-1$ perpendicular lines. So instead of using the original data for the midline, it would probably make sense to smooth it (using some spline interpolation) and then sample the spline to get one more point than the number of perpendicular lines you want.



              The second task is a bit tricker. It looks like the carrot shape is more or less convex which means you could essentially define the boundary as a bunch of hyperplanes, and then see where the line from task 1 intersects them. I'm sure there are libraries for this, and if you search "intersect line with convex shape" there are lots of results.



              Another thought is to find the points on the boundary such that the slope between the point on the midline and the boundary point is as close to possible as the slope of the normal at the point on the midline. Once you have those points, you can then compute the distance to them from the midline point.



              If speed is a concern, searching for these points can probably be done using some kind of bisection.



              Sample code



              enter image description here



              We store the boudary points in an array of points called boundary (black points) and the midline in an array of points called midline (red points). The following code identifies the two blue points which approximate the intersection of the normal line (in grey) with the boundary.



              The first task is to find the unit tangent at a point. We can do this for all points simultaneously:



              slopes = midline[1:] - midline[:-1]
              tangents = [1,-1]*slopes[:,::-1]
              tangents /= np.linalg.norm(tangents,axis=1)[:,None]


              Now suppose you have a known point p on and a known direction n.
              We first compute the direction from p to each boundary point.



              vec_to_boundary = (boundary - p)
              vec_to_boundary /= np.linalg.norm(slope_to_boundary,axis=1)[:,None]


              Now compute the inner product with each of these vectors.



              inner_product_normal = slope_to_boundary@n



              The largest (in magnitude) inner products will tell us which points on the boundary are closest to the normal line passing through p.



              b0 = np.argmax(inner_product_normal)
              b1 = np.argmin(inner_product_normal)


              Finally, we can approximate the distance to the boundary from p along n as the distance to the boundary points we found.



              d1 = np.linalg.norm(boundary[b0] - p)
              d2 = np.linalg.norm(boundary[b1] - p)


              Note that for this to work well you need that the boundary have enough points that the stored boundary points are "close" to the intersection of the normal line with the "true" boundary. It also assumes the boundary is convex. In practice you will probably have to smooth the midline and boundary before using this type of approach.






              share|cite|improve this answer











              $endgroup$
















                0












                0








                0





                $begingroup$

                I think the two big steps are 1. finding the perpendicular lines to the midline, and 2. finding the distance to the edge along these lines.



                The first task is relatively straightforward. Suppose the midline is defined by the points $(x_1,y_1), (x_2,y_2), ldots, (x_k,y_k)$. You can find the tangent vector $(Delta x,Delta y) = (x_2-x_1,y_2-y_1)$ at a point $(x_1,y_1)$, and then find the vector orthogonal to this: $ (-Delta y, Delta x) $ and normalize it.



                Now, note that you will get $k-1$ perpendicular lines. So instead of using the original data for the midline, it would probably make sense to smooth it (using some spline interpolation) and then sample the spline to get one more point than the number of perpendicular lines you want.



                The second task is a bit tricker. It looks like the carrot shape is more or less convex which means you could essentially define the boundary as a bunch of hyperplanes, and then see where the line from task 1 intersects them. I'm sure there are libraries for this, and if you search "intersect line with convex shape" there are lots of results.



                Another thought is to find the points on the boundary such that the slope between the point on the midline and the boundary point is as close to possible as the slope of the normal at the point on the midline. Once you have those points, you can then compute the distance to them from the midline point.



                If speed is a concern, searching for these points can probably be done using some kind of bisection.



                Sample code



                enter image description here



                We store the boudary points in an array of points called boundary (black points) and the midline in an array of points called midline (red points). The following code identifies the two blue points which approximate the intersection of the normal line (in grey) with the boundary.



                The first task is to find the unit tangent at a point. We can do this for all points simultaneously:



                slopes = midline[1:] - midline[:-1]
                tangents = [1,-1]*slopes[:,::-1]
                tangents /= np.linalg.norm(tangents,axis=1)[:,None]


                Now suppose you have a known point p on and a known direction n.
                We first compute the direction from p to each boundary point.



                vec_to_boundary = (boundary - p)
                vec_to_boundary /= np.linalg.norm(slope_to_boundary,axis=1)[:,None]


                Now compute the inner product with each of these vectors.



                inner_product_normal = slope_to_boundary@n



                The largest (in magnitude) inner products will tell us which points on the boundary are closest to the normal line passing through p.



                b0 = np.argmax(inner_product_normal)
                b1 = np.argmin(inner_product_normal)


                Finally, we can approximate the distance to the boundary from p along n as the distance to the boundary points we found.



                d1 = np.linalg.norm(boundary[b0] - p)
                d2 = np.linalg.norm(boundary[b1] - p)


                Note that for this to work well you need that the boundary have enough points that the stored boundary points are "close" to the intersection of the normal line with the "true" boundary. It also assumes the boundary is convex. In practice you will probably have to smooth the midline and boundary before using this type of approach.






                share|cite|improve this answer











                $endgroup$



                I think the two big steps are 1. finding the perpendicular lines to the midline, and 2. finding the distance to the edge along these lines.



                The first task is relatively straightforward. Suppose the midline is defined by the points $(x_1,y_1), (x_2,y_2), ldots, (x_k,y_k)$. You can find the tangent vector $(Delta x,Delta y) = (x_2-x_1,y_2-y_1)$ at a point $(x_1,y_1)$, and then find the vector orthogonal to this: $ (-Delta y, Delta x) $ and normalize it.



                Now, note that you will get $k-1$ perpendicular lines. So instead of using the original data for the midline, it would probably make sense to smooth it (using some spline interpolation) and then sample the spline to get one more point than the number of perpendicular lines you want.



                The second task is a bit tricker. It looks like the carrot shape is more or less convex which means you could essentially define the boundary as a bunch of hyperplanes, and then see where the line from task 1 intersects them. I'm sure there are libraries for this, and if you search "intersect line with convex shape" there are lots of results.



                Another thought is to find the points on the boundary such that the slope between the point on the midline and the boundary point is as close to possible as the slope of the normal at the point on the midline. Once you have those points, you can then compute the distance to them from the midline point.



                If speed is a concern, searching for these points can probably be done using some kind of bisection.



                Sample code



                enter image description here



                We store the boudary points in an array of points called boundary (black points) and the midline in an array of points called midline (red points). The following code identifies the two blue points which approximate the intersection of the normal line (in grey) with the boundary.



                The first task is to find the unit tangent at a point. We can do this for all points simultaneously:



                slopes = midline[1:] - midline[:-1]
                tangents = [1,-1]*slopes[:,::-1]
                tangents /= np.linalg.norm(tangents,axis=1)[:,None]


                Now suppose you have a known point p on and a known direction n.
                We first compute the direction from p to each boundary point.



                vec_to_boundary = (boundary - p)
                vec_to_boundary /= np.linalg.norm(slope_to_boundary,axis=1)[:,None]


                Now compute the inner product with each of these vectors.



                inner_product_normal = slope_to_boundary@n



                The largest (in magnitude) inner products will tell us which points on the boundary are closest to the normal line passing through p.



                b0 = np.argmax(inner_product_normal)
                b1 = np.argmin(inner_product_normal)


                Finally, we can approximate the distance to the boundary from p along n as the distance to the boundary points we found.



                d1 = np.linalg.norm(boundary[b0] - p)
                d2 = np.linalg.norm(boundary[b1] - p)


                Note that for this to work well you need that the boundary have enough points that the stored boundary points are "close" to the intersection of the normal line with the "true" boundary. It also assumes the boundary is convex. In practice you will probably have to smooth the midline and boundary before using this type of approach.







                share|cite|improve this answer














                share|cite|improve this answer



                share|cite|improve this answer








                edited Dec 19 '18 at 19:33

























                answered Dec 19 '18 at 16:54









                tchtch

                833310




                833310






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Mathematics Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmath.stackexchange.com%2fquestions%2f3045932%2ffinding-arrays-of-pixels-perpendicular-to-a-derivative%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Plaza Victoria

                    In PowerPoint, is there a keyboard shortcut for bulleted / numbered list?

                    How to put 3 figures in Latex with 2 figures side by side and 1 below these side by side images but in...