Writing a multipage tif to file in matlab - image

I'm trying to write a a multipage (1024 pages to be exact) to file.
for frame=1:num_images
imwrite(output(:,:,frame), 'output.tif', 'tif', 'WriteMode', 'append', 'compression', 'none');
end
I tried this, but writing Int32 to tiff is not supported by imwrite.
I've also tried
tiffObj = Tiff('output.tif', 'w');
tiffObj.setTag('ImageLength', x_size);
tiffObj.setTag('ImageWidth', y_size);
tiffObj.setTag('Photometric', Tiff.Photometric.MinIsBlack);
tiffObj.setTag('BitsPerSample', 32);
tiffObj.setTag('SamplesPerPixel', 1);
tiffObj.setTag('RowsPerStrip', 64);
tiffObj.setTag('SampleFormat', Tiff.SampleFormat.Int);
tiffObj.setTag('TileWidth', 128);
tiffObj.setTag('TileLength', 128);
tiffObj.setTag('Compression', Tiff.Compression.None);
tiffObj.setTag('PlanarConfiguration',Tiff.PlanarConfiguration.Chunky);
tiffObj.setTag('Software', 'MATLAB');
tiffObj.write(output);
tiffObj.close();
The tif I imread() has 1 SamplesPerPixel per frame, but when I try to use the same value I get
SamplesPerPixel is 1, but the number of image planes provided was 1204.
If I set it to 1204 Imagej complains
Unsupported SamplesPerPixel: 1204
This is rather frustrating.

The correct way to write multiple pages to a TIFF file is to call Tiff.writeDirectory after each page (2D image) has been written. I agree, the MATLAB documentation is not very clear there, knowing LibTIFF helps in using the Tiff class. For example:
image = zeros([140,160,16],'uint8'); % this is the image we'll write, should have some actual data in it...
t = Tiff('testing.tif','w');
tagstruct.ImageLength = size(image,1);
tagstruct.ImageWidth = size(image,2);
tagstruct.SampleFormat = 1; % uint
tagstruct.Photometric = Tiff.Photometric.MinIsBlack;
tagstruct.BitsPerSample = 8;
tagstruct.SamplesPerPixel = 1;
tagstruct.Compression = Tiff.Compression.Deflate;
tagstruct.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
for ii=1:size(image,3)
setTag(t,tagstruct);
write(t,image(:,:,ii));
writeDirectory(t);
end
close(t)

Related

Writing Macro in ImageJ to open, change color, adjust brightness and resave microscope images

I'm trying to write a code in Image J that will:
Open all images in separate windows that contains "488" within a folder
Use look up tables to convert images to green and RGB color From ImageJ, the commands are: run("Green"); and run("RGB Color");
Adjust the brightness and contrast with defined values for Min and Max (same values for each image).
I know that the code for that is:
//run("Brightness/Contrast..."); setMinAndMax(value min, value max); run("Apply LUT");
Save each image in the same, original folder , in Tiff and with the same name but finishing with "processed".
I have no experience with Java and am very bad with coding. I tried to piece something together using code I found on stackoverflow and on the ImageJ website, but kept getting error codes. Any help is much appreciated!
I don't know if you still need it, but here is an example.
output_dir = "C:/Users/test/"
input_dir = "C:/Users/test/"
list = getFileList(input_dir);
listlength = list.length;
setBatchMode(true);
for (z = 0; z < listlength; z++){
if(endsWith(list[z], 'tif')==true ){
if(list[z].contains("488")){
title = list[z];
end = lengthOf(title)-4;
out_path = output_dir + substring(title,0,end) + "_processed.tif";
open(input_dir + title);
//add all the functions you want
run("Brightness/Contrast...");
setMinAndMax(1, 15);
run("Apply LUT");
saveAs("tif", "" + out_path + "");
close();
};
run("Close All");
}
}
setBatchMode(false);
I think it contains all the things you need. It opens all the images (in specific folder) that ends with tif and contains 488. I didn't completely understand what you want to do with each photo, so I just added your functions. But you probably won't have problems with adding more/different since you can get them with macro recorder.
And the code is written to open tif files. If you have tiff just be cerful that you change that and also change -4 to -5.

Using MATLAB to save a montage of many images as one large image file at full resolution

I am trying to save a montage of many (~500, 2MB each) images using MATLAB function imwrite, however I keep getting this error:
Error using imwrite>validateSizes (line 632)
Images must contain fewer than 2^32 - 1 bytes of data.
Error in imwrite (line 463)
validateSizes(data);
here is the code I am working with:
close all
clear all
clc
tic
file = 'ImageRegistrations.txt';
info = importdata(file);
ImageNames = info.textdata(:,1);
xoffset = info.data(:,1);
yoffset = info.data(:,2);
for i = 1:length(ImageNames);
ImageNames{i,1} = imread(ImageNames{i,1});
ImageNames{i,1} = flipud(ImageNames{i,1});
end
ImageNames = flipud(ImageNames);
for i=1:length(ImageNames)
diffx(i) = xoffset(length(ImageNames),1) - xoffset(i,1);
end
diffx = (diffx)';
diffx = flipud(diffx);
for j=1:length(ImageNames)
diffy(j) = yoffset(length(ImageNames),1) - yoffset(j,1);
end
diffy = (diffy)';
diffy = flipud(diffy);
matrix = zeros(max(diffy)+abs(min(diffy))+(2*1004),max(diffx)+abs(min(diffx))+(2*1002));
%matrix(1:size(ImageNames{1,1},1),1:size(ImageNames{1,1},2)) = ImageNames{1,1};
for q=1:length(ImageNames)
matrix((diffy(q)+abs(min(diffy))+1):(diffy(q)+abs(min(diffy))+size(ImageNames{q,1},1)),(diffx(q)+abs(min(diffx))+1):((diffx(q)+abs(min(diffx))+size(ImageNames{q,1},2)))) = ImageNames{q,1};
end
graymatrix = mat2gray(matrix);
graymatrix = flipud(graymatrix);
figure(2)
imshow(graymatrix)
imwrite(graymatrix, 'montage.tif')
toc
I use imwrite because it perserves the final montage in a full resolution file, whereas if I simply click save on the figure file it saves it as a low resolution file.
thanks!
Error does what it says on the tin, really. There is some sort of inbuilt limitation to input variable size in imwrite, and you're going over it.
Note that most images are stored as uint8 but I would guess that you end up with doubles as a result of your processing. That increases the memory usage.
It may be, therefore, that casting to another type would help. Try using im2uint8 (presuming your variable graymatrix is double, scaled between 0 and 1), before calling imwrite.

Creating Image stacks and writing GDF file

I am attempting to write a function that stack up series of images into image stack and converting it into a gdf file. I don't really know much about GDF files, so please help me out.
X=[];
for i=1:10
if numel(num2str(i))==1
X{i}=imread(strcat('0000',num2str(i),'.tif'));
elseif numel(num2str(i))==2
X{i}=imread(strcat('000',num2str(i),'.tif'));
end
end
myImage=cat(3,X{1:10});
s=write_gdf('stack.gdf',myImage);
Above is to read my images labeled 00001 to 00010, all in grayscale. Everything is fine except in the last line
s=write_gdf('stack.gdf',myImage);
as when I run it, I receive an error:
Data type uint8 not supported
Any help on what this means? Should I convert it to some other colour format?
Thank you in advance!
I would write the code rather like this (I do not have write_gdf function so I can not properly test the code):
NumberOfFiles = 10;
X={}; % preallocate CELL array
for n=1:NumberOfFiles % do not use "i" as your varable because it is imaginary unit in MatLab
FileName = sprintf('%05d.tif',n);
img = imread(FileName); % load image
X{i} = double(img); % and convert to desired format
end
myImage = cat(3,X{1:NumberOfFiles});
s = write_gdf('stack.gdf',myImage);
Keep in mind that
double(img); % and convert to desired format
will not change data range. Your image even in double format will have data range from 0 to 255 if it was in uint8 format on disk. If you need to normalize your data to 0..1 range you should do
X{i} = double(img)/255;
or in more unversal form
X{i} = double(img) / intmax(class(img));

Rendering smallest possible image size with MVC3 vs Webforms Library

I am in the process of moving a webforms app to MVC3. Ironically enough, everything is cool beans except one thing - images are served from a handler, specifically the Microsoft Generated Image Handler. It works really well - on average a 450kb photo gets output at roughly 20kb.
The actual photo on disk weighs in at 417kb, so i am getting a great reduction.
Moving over to MVC3 i would like to drop the handler and use a controller action. However i seem to be unable to achieve the same kind of file size reduction when rendering the image. I walked through the source and took an exact copy of their image transform code yet i am only achieving 230~kb, which is still a lot bigger than what the ms handler is outputting - 16kb.
You can see an example of both the controller and the handler here
I have walked through the handler source code and cannot see anything that is compressing the image further. If you examine both images you can see a difference - the handler rendered image is less clear, more grainy looking, but still what i would consider satisfactory for my needs.
Can anyone give me any pointers here? is output compression somehow being used? or am i overlooking something very obvious?
The code below is used in my home controller to render the image, and is an exact copy of the FitImage method in the Image Transform class that the handler uses ...
public ActionResult MvcImage()
{
var file = Server.MapPath("~/Content/test.jpg");
var img = System.Drawing.Image.FromFile(file);
var sizedImg = MsScale(img);
var newFile = Server.MapPath("~/App_Data/test.jpg");
if (System.IO.File.Exists(newFile))
{
System.IO.File.Delete(newFile);
}
sizedImg.Save(newFile);
return File(newFile, "image/jpeg");
}
private Image MsScale(Image img)
{
var scaled_height = 267;
var scaled_width = 400;
int resizeWidth = 400;
int resizeHeight = 267;
if (img.Height == 0)
{
resizeWidth = img.Width;
resizeHeight = scaled_height;
}
else if (img.Width == 0)
{
resizeWidth = scaled_width;
resizeHeight = img.Height;
}
else
{
if (((float)img.Width / (float)img.Width < img.Height / (float)img.Height))
{
resizeWidth = img.Width;
resizeHeight = scaled_height;
}
else
{
resizeWidth = scaled_width;
resizeHeight = img.Height;
}
}
Bitmap newimage = new Bitmap(resizeWidth, resizeHeight);
Graphics gra = Graphics.FromImage(newimage);
SetupGraphics(gra);
gra.DrawImage(img, 0, 0, resizeWidth, resizeHeight);
return newimage;
}
private void SetupGraphics(Graphics graphics)
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighSpeed;
}
If you don't set the quality on the encoder, it uses 100 by default. You'll never get a good size reduction by using 100 due to the way image formats like JPEG work. I've got a VB.net code example of how to set the quality parameter that you should be able to adapt.
80L here is the quality setting. 80 still gives you a fairly high quality image, but at DRASTIC size reduction over 100.
Dim graphic As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(newImage)
graphic.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
graphic.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality
graphic.PixelOffsetMode = Drawing.Drawing2D.PixelOffsetMode.HighQuality
graphic.CompositingQuality = Drawing.Drawing2D.CompositingQuality.HighQuality
graphic.DrawImage(sourceImage, 0, 0, width, height)
' now encode and send the new image
' This is the important part
Dim info() As Drawing.Imaging.ImageCodecInfo = Drawing.Imaging.ImageCodecInfo.GetImageEncoders()
Dim encoderParameters As New Drawing.Imaging.EncoderParameters(1)
encoderParameters.Param(0) = New Drawing.Imaging.EncoderParameter(Drawing.Imaging.Encoder.Quality, 80L)
ms = New System.IO.MemoryStream
newImage.Save(ms, info(1), encoderParameters)
When you save or otherwise write the image after setting the encoder parameters, it'll output it using the JPEG encoder (in this case) set to quality 80. That will get you the size savings you're looking for.
I believe it's defaulting to PNG format also, although Tridus' solution solves that also.
However, I highly suggest using this MVC-friendly library instead, as it avoids all the image resizing pitfalls and doesn't leak memory. It's very lightweight, free, and fully supported.

How to convert Single Channel IplImage* to Bitmap^

How can I convert single channel IplImage (grayscale), depth=8, into a Bitmap?
The following code runs, but displays the image in 256 color, not grayscale. (Color very different from the original)
btmap = gcnew Bitmap(
cvImg->width ,
cvImg->height ,
cvImg->widthStep ,
System::Drawing::Imaging::PixelFormat::Format8bppIndexed,
(System::IntPtr)cvImg->imageData)
;
I believe my problem lies in the PixelFormat. Ive tried scaling the image to 16bit and setting the pixel format to 16bppGrayscale, but this crashes the form when uploading the image.
The destination is a PicturePox in a C# form.Thanks.
You need to create ColorPalette instance, fill it with grayscale palette and assign to btmap->Palette property.
Edit: Actually, creating ColorPalette class is a bit tricky, it is better to modify color entries directly in btmap->Palette. Set these entries to RGB(0,0,0), RGB(1,1,1) ... RGB(255,255,255). Something like this:
ColorPalette^ palette = btmap->Palette;
array<Color>^ entries = palette->Entries;
for ( int i = 0; i < 256; ++i )
{
entries[i] = Color::FromArgb(i, i, i);
}
int intStride = (AfterHist.width * AfterHist.nChannels + 3) & -4;
Bitmap BMP = new Bitmap(AfterHist.width,
AfterHist.height, intStride,
PixelFormat.Format24bppRgb, AfterHist.imageData);
this way is correct to create a bitmap of a IPLimage.

Resources