How to redistribute pixels?

Asked by Tony D on 26 Jan 2013
Latest activity Commented on by Matt J on 25 Mar 2013

Posted is a picture of a cross section of a vein. I have transformed the red interior line into a circle and need to have the pixels on the black line surround the new circular red line, both red and black lines having the same centers. The transformed black line should not be a perfect circle. As you can see in the picture, the distance between the black and red lines differ and once the black line is transformed, it should maintain the same varying distance between it and the red line as before. My question is how can I do this?

0 Comments

Tony D

Products

2 Answers

Answer by Image Analyst on 27 Jan 2013

It's not too hard if you think about it systematically. Just take it one step at a time. The key is to convert the lines into masks and use bwdist().

  1. use poly2mask on the black line to get a mask
  2. use poly2mask on the red line to get a smaller mask
  3. subtract the two masks to get the "in between" region.
  4. call bwdist() to get the Euclidean Distance Transform (EDT). This is the distance from the region to the nearest edge, so twice that is the thickness of the region at that point. So multiply the EDT by 2.
  5. call bwmorph() to get the skeleton. This is the centerline of the region.
  6. Multiply the skeleton by the EDT. This will give you the thickness of the region.
  7. bwdist will also give you the pixel on the red line that is closest to the black line.
  8. Now you know the radius and center of the red circle. Radius is just perimeter/(2*pi). So you just run around the black circle, and get the red pixel that is closest to it.
  9. You know the position of each red pixel - it's index on the circle. So you plot a red point there, and then plot a black point at that red radius plus 2*EDT for that black pixel.

4 Comments

Image Analyst on 29 Jan 2013

(4) The region thickness is twice the EDT value at the center. Let's say you had a region 20 pixels wide. Well, at the center it will be 10 pixels to either side because if you're at the center line it has to go only half the thickness to get outside the region. So you need to double the value at the center to get the full thickness.

6) You multiply by the skeleton to give you the value along the centerline of the region. The EDT you get in (4) is a thick image. It's like a wide swatch the same size as the region in between your two curves. And the values of the EDT go from 0 or 1 at the edge (where a pixel inside the swath does not have far to go to get outside) all the way to half the thickness at the centerline. If you're 3 pixels away from the background, the EDT value is 3, if you're 4 pixels away it's 5, if you're 5 pixels away it's 5, and so on until you're the radius (half thickness) away from the edge. If you proceed toward the other side, it starts going down again until it again reaches 0 at the other edge (boundary).

Think of it like this. You're taking an inflatable ball and running it along the region between the two lines. The ball is always inflated as much as it can go and still be a circle. Sometimes, when the thickness is large, you can fit a large ball, and sometimes, when the thickness is small, you'll have a small ball. The EDT along the centerline (skeleton, spine) is the radius of the ball at that point.

Does that explain it better?

Tony D on 30 Jan 2013

Thanks for the clarification, I understand what the EDT and skeleton are now. So far I have: #1 created the masks #2 gotten the "in between" region and made it hollow #3 did a EDT calc between the two boundary lines of the region #4 found the skeleton of the hollow region #5 removed the branches from the skeleton (don't know purpose of branches) #6 found the perimeter of the region that will be transformed in a circle #7 used that perimeter to find the diameter for the transformed circle

When I did the EDT it gave me a giant "logic" matrix. So now how can I use MATLAB to go through all of the pixels on a boundary of the matrix and find the distance to the nearest pixel on the opposing line?

I appreciate your help.

Tony D on 30 Jan 2013

Or is there a way of taking a pixel on a line, lets say the black line, and then find the shortest path to the red line and storing that path as a vector?

Image Analyst
Answer by Matt J on 4 Feb 2013

So now how can I use MATLAB to go through all of the pixels on a boundary of the matrix and find the distance to the nearest pixel on the opposing line?

If the rows of A are the pixel coordinates on the black line and B the red line, then you can use

http://www.mathworks.com/matlabcentral/fileexchange/18937-ipdm-inter-point-distance-matrix

as follows

s=ipdm(A,B,'Subset', 'NearestNeighbor','Result','Structure');

Then s.columnindex will be the indices in B of the closest points on the red line. The corresponding distances will be in s.distance.

When run with this specific syntax, the column index is what will be most useful. It tells you that

 B(short_dist.columnindex(i), :)

is the closest point on the red line to A(i,:). And if you want the vector between the two points, just do

 B(short_dist.columnindex(i), :) - A(i,:)

for all i=1...1856. Or, in vectorized form, simply

 B(short_dist.columnindex, :) - A

35 Comments

Matt J on 19 Mar 2013

Can you see any way in which I can do the transform that I want using the given specifications?

Well, here's another idea. You're already using imfreehand or similar to trace the boundary of the curves. It seems to me that it would be essentially the same manual effort to use IMLINE or similar to draw lots of closely spaced line segments connecting the black curve to the red curve (essentially the pre-chords that we've been talking about). You would do this according to your own visual idea of which points on the black and red curves correspond, as opposed to using IPDM.

Once you've done that, you map all the points on the black curve to the desired circle. You would probably do this so that the distances between neighboring black points are all the same post-transformation as they were pre-transformation. You then use the lengths of the pre-chords to construct post-chords of the same length, except that the post chords are all directed inward toward the center of the black circle. The inner endpoints of the post-chords define the points on the transformed red curve and you're done.

Assuming you pack the pre-chords densely enough, you should get a pretty good approx of the curve you're looking for. Assuming, further, that a transform preserving both chord length and area does exist, I would expect this manual approach to do a fair bit better than the 8% area agreement you got via IPDM. If you don't get good area preservation, it would suggest to me that the requirements of chord length preservation and area preservation are in conflict. In either case, I wonder if you should really be caring about preserving distance and area so precisely. It sounds to me like you're planning to use this anyway as nothing more than an ad hoc initial approximation to something that's going to be refined later using something more principled (FEA?).

Tony D on 25 Mar 2013

Could I preserve area by multiplying the transformed curves by sqrt(A_orig/A_new)?

Matt J on 25 Mar 2013

I don't know what it means to "multiply a curve" by something. If you mean to scale the chord lengths by that, then perhaps, but then chord-length won't be preserved.

Matt J

Contact us