How do I "grow" an image?

Hello,

how do I accomplish the following: I extract a line from an image. From this I would like to create an image with width identical to the length of the line and the height should be specified. The pixel values in each line in the new image should be identical to the single line, with which I started.

I tried the image – scale command, but it does not give me what I want.

Hermann-Josef

Hi @Jossie,

The function you are looking for might be Straighten.
You can specify the height of the resulting image by changing the width of the Line.

Cheers,

Romain

1 Like

Hello @romainGuiet,

thanks for your answer. I tried the straighten command. It comes close but is not quite what I wanted. The lines in the new image should all be the same pixel values as the original line, i.e. in the columns the values should be constant. This is not the case with the straighten command. Anyhow, it might come close to what I wanted.

Hermann-Josef

Hi Jossie,

here’s a python script that does what I think you want. It gets the profile from the a line Roi (what is plotted in the Analyze > Plot Profile command) and creates new image of this length and a specified height.

It’s compatible with Hyperstacks and straight, segmented, curved, etc lines.

25%20pm

Cheers,

Chris

from ij import IJ,ImagePlus

def grow_line(imp, height):
	''' Creates a new image by taking the prfile from a line Roi and growing it
		imp    - image with a line Roi
		height - ammount to grow by 
	If there is no line Roi None is returned'''
	roi = imp.getRoi()
	if( roi and (roi.getType() in [ roi.LINE, roi.POLYLINE, roi.FREELINE ]) ) :
	
		from ij.gui import ProfilePlot
		prof = ProfilePlot(imp).getProfile()
		print(type(prof))
		width = len(prof)

		[_, _, nChannels, nSlices, nFrames]=imp.getDimensions()
		imp_grow= IJ.createHyperStack(imp.getTitle()+"-grow", width,height, nChannels, nSlices, nFrames, imp.getBitDepth() )

		for c in range(nChannels):
			for z in range(nSlices):
				for t in range(nFrames):
					imp.setPositionWithoutUpdate(c+1, z+1, t+1)
					prof = ProfilePlot(imp).getProfile()
					
					imp_grow.setPositionWithoutUpdate(c+1, z+1, t+1)
					ip_grow=imp_grow.getProcessor()
					for i in range(height):
						ip_grow.putRow(0,i,map(float,prof),width)
		return imp_grow
	else:
		return None
	
	
if( __name__=="__builtin__"):
	imp = IJ.getImage()
	imp_grow = grow_line( imp, 50 )
	if( imp_grow ):
		imp_grow.show()

@evenhuis
Thanks for your efforts! Yes, this looks indeed exactly what I was looking for.

I do not speak Python. Can I just create an imageJ plugin from this code or do I have to adopt this to Java?

Hermann-Josef

Hi Jossie,

  1. Save the code in this message as “Grow_Line.py” (you can rename it as long as there is an underscore somewhere in the name).
  2. Copy it into the plugins folder for your ImageJ application
  3. Restart ImageJ
  4. It will be in the Plugins menu

Cheers,

Chris

#@ Integer (label="Grow a line", description="height") height
from ij import IJ,ImagePlus

def grow_line(imp, height):
	''' Creates a new image by taking the prfile from a line Roi and growing it
		imp    - image with a line Roi
		height - ammount to grow by 
	If there is no line Roi None is returned'''
	roi = imp.getRoi()
	if( roi and (roi.getType() in [ roi.LINE, roi.POLYLINE, roi.FREELINE ]) ) :
	
		from ij.gui import ProfilePlot
		prof = ProfilePlot(imp).getProfile()
		print(type(prof))
		width = len(prof)

		[_, _, nChannels, nSlices, nFrames]=imp.getDimensions()
		imp_grow= IJ.createHyperStack(imp.getTitle()+"-grow", width,height, nChannels, nSlices, nFrames, imp.getBitDepth() )

		for c in range(nChannels):
			for z in range(nSlices):
				for t in range(nFrames):
					imp.setPositionWithoutUpdate(c+1, z+1, t+1)
					prof = ProfilePlot(imp).getProfile()
					
					imp_grow.setPositionWithoutUpdate(c+1, z+1, t+1)
					ip_grow=imp_grow.getProcessor()
					for i in range(height):
						ip_grow.putRow(0,i,map(float,prof),width)
		return imp_grow
	else:
		return None
	
	
if( __name__=="__builtin__"):
	imp = IJ.getImage()
	imp_grow = grow_line( imp, height )
	if( imp_grow ):
		imp_grow.show()

@evenhuis Hi Chris,

I did as you said. I opened an image in imageJ and created a straight line as ROI. When I run the plugin, it first downloaded the Jython.jar. But then nothing happened, even after restarting imageJ and trying again.

I use imageJ 1.52n

Hermann-Josef

Hi Jossie,

Does it work if you run it in the script editor?

  1. Open a new script: File > New > Script...
  2. Set the language to Python: Language > Python
  3. Case the code into in box
  4. Click on an Image and draw a line Roi
  5. Press Run in the script window.

A dialog box should pop up asking you the height.

Cheers,

Chris

Hello Chris,

I am afraid you are talking about a different setup (my imageJ version is 1.52n). In my imageJ there is no File > New > Script. I can only edit a macro or a plugin. There is no place to select Python as language.

Hermann-Josef

Ah, go download Fiji. It’s ImageJ with a standard set of plugins, like a script editor.

@evenhuis Okay, that will explain the difference.

However, it may take a while till I have made the transition. I have quite a few important macros for imageJ and I must make sure they will work under Fiji.

Thanks again for your help!

Hermann-Josef

If I’m understanding correctly, you can accomplish this without scripting by using the Edit > Selection > Straighten command, described by @romainGuiet (using a line width of 1 px) to create an image with a height of 1 pixel. then to “grow” the line just use Image > Adjust > Size … but make sure to uncheck “constrain aspect ratio”. Set the width to the existing image width, and the height to whatever you want it to be. The values in each row will then be identical to the original line.

1 Like

@talley

Good morning,

thanks for your advice. It works as you described with only one more thing to clarify: The pixel values in the output image are constant in each column, as is desired. However, their values are not the same as in the input image.

Here is a plot of the original line selected:
image
And this is a plot along a line in the output image with interpolation set to “none”:
image
If everything would be as I wanted, the two plots should be identical.
Setting the interpolation to “bilinear” does give a different result, but also not the desired one.

However, if I separate the channels and do all this individually for each channel, then the pixel values are correct. The problem seems to be that the straighten command produces an RGB-image from the 3-channel 16bit original.

So I will have to combine the results from the 3 channels again to get a 16bit 3-channel TIF.

Perhaps I should briefly mention, what I want to do: The dark subtraction for my scanner is not 100% correct. There remains a pattern along the CCD. Since the scan is done line by line, the pattern should be constant in the vertical direction. Thus I want to extract the pattern from an image as a single line, “grow” this image so I have an image of the same size as the original TIF and subtract this from all scans. This should get rid of the vertical stripes in the images. Here is an example with slight vertical banding I want to correct for:

Hermann-Josef

start the transition as soon as you can
all the macros you are using will work in fiji.
but in Fiji you’ll have more opportunities and more analysis tools ready to use.
and secondly but not less important the larger part of the community (I would like to say the whole community) is using fiji and it will be much more easier and faster ask and receive help.

One possibility that I see for eliminating the stripes:

  • Duplicate the upper half of the image (the sky)
  • If you need 32-bit (floating-point) data at a later stage (see below), convert to 32 bit now.
  • Image>Adjust>Size leaving the width as it is, height=1, with interpolation=none, average when downsizing.
  • Image>Adjust>Size to the size of the original image
    Then you should get the stripe pattern.
  • I guess that you will then have to divide by the “stripe image”, not subtract it, but you need to do this with floating-point accuracy. Normalize the image channels of the stripe image to one (divide each by the mean of the channel).
  • If the gradient from left to right is true image information, you should eliminate it in the stripe image. Duplicate the stripe image, run a Gaussian Blur with large radius over it, and divide the stripe image by the blurred one. This replaces the normalization step.
  • Finally, use the Image Calculator to divide the original image by the normalized stripe image.
    If you need a 16-bit image and the result has 32 bits, set the range in Brightness&contrast to 0–65535 and convert to 16 bits.
    –Michael

@Schmid Hello Michael,

thanks you for the detailed recipe.

I have test scans from which I can derive the stripe pattern. If this is dark current it has to be subtracted and not divided. I am confident that this will work out, now that I know how to “grow” the one-dimensional pattern I derived from the test scans. The image I showed was just to illustrate what I am after. I am afraid it will not work for all images to derive the pattern individually from each image.

Hermann-Josef

Hi Hermann-Josef,
ok, if it is always the same pattern, and if it is just a dark current, it’s easier. Nevertheless, due to noise, you should first average over many lines:

  • Take an image of a uniform area, then
  • Image>Adjust>Size leaving the width as it is, height=1, with interpolation=none, average when downsizing.
  • Image>Adjust>Size to the size of the image where you want to subtract the stripes.

In Image>Adjust>Size, you have to deselect the ‘Constrain Aspect Ratio’, then you can convert an image with, e.g., a width of 1200 pxl and a height of 1 pxl (a single line) to any height that you like, e.g., 1200x900 pxl.
– Michael