Rename multi-frame dicom images - matlab

I have a dicom file that contains 110 images and their names are random. I am trying to rename them according to their SliceLocations (n) and rewrite them with the dcm extension, i.e., n(1).dcm, n(2).dcm, …
Any suggestions would be appreciated.
I tried
image_list=dir('*.dcm');
for i=1:110
img=dicomread(image_list);
imgHdr = dicominfo(image_list(i).name);
for j = size(img,4);
dicomwrite(img(:,:,:,j),['n(' int2str(j) ').dcm'],imgHdr,'CreateMode','Copy');
end
end

Slice location (0020,1041) is an optional attribute for image plane module. There is no guarantee that tag will have any value. Your best option is to use the Image Position (Patient) (0020, 0032) attribute. This will have x, y, and z coordinates of the upper left hand corner (center of the first voxel transmitted) of the image. See DICOM standard PS 3.3 - 2011 (PDF), Annex C.7.6.2.1, for further explanation.

NOTE: This answer applies to "frames," not "slices." The two are apparently different things for DICOM files.
One convenient option, if you don't need exactly the naming scheme in your question, is to use the 'MultiframeSingleFile' option in the dicomwrite function:
X = dicomread('MultiFrameFile.dcm');
dicomwrite(X,'n.dcm','MultiframeSingleFile',false);
This will produce files named 'n_01.dcm', 'n_02.dcm', ...
Otherwise you can use a simple for loop in conjunction with int2str:
X = dicomread('MultiFrameFile.dcm');
for i = size(X,4);
dicomwrite(X(:,:,:,i),['n(' int2str(i) ').dcm']);
end

Related

How to get region with lowest y value in the centroid

I have a binary image that has two connected components. Both are fairly horizontal and one is on the top of the image and the other at the bottom. What I need to do is to extract only the top component which I want to do (or at least what I think is a good method) by taking the component with the lowest y value for the centroid (because MATLAB uses Java to show images, so the origin is at the top left) and erasing the other component. So far I've been able to use regionprops to find which region has the lowest y value for the centroid, but from there I'm not sure how to get a binary image back again with the component I want.
I've read in the documentation that bwconncomp, labelmatrix, and ismember are useful, but I'm not very sure how to use them well (or at all very much).
This is the solution I just made up, but if there's a better or more elegant one I'd love to know about it!
P.S. filtered is my image
connComp = bwconncomp(filtered);
props = regionprops(filtered, 'Centroid');
justTop = zeros(size(filtered,1), size(filtered,2));
if props(1).Centroid(2) > props(2).Centroid(2)
justTop(connComp.PixelIdxList{2}) = 1;
else
justTop(connComp.PixelIdxList{1}) = 1;
end`

insert text into image without computer vision system toolbox - Matlab

In the Matlab central (http://www.mathworks.com/matlabcentral/answers/26033-how-to-insert-text-into-image) I found this code:
Text = sprintf('Create text inserter object \nwith same property values');
H = vision.TextInserter(Text);
H.Color = [1.0 1.0 0];
H.FontSize = 20;
H.Location = [25 25];
I = im2double((imread('football.jpg')));
InsertedImage = step(H, I);
imshow(InsertedImage);
How can I do the same without using the computer vision system toolbox?
Thanks
To follow up on my comment:
A = imread('football.jpg');
YourText = sprintf('Create text inserter object \nwith same property values');
figure;
imshow(A);
hText = text(25,25,YourText,'Color',[1 1 0],'FontSize',20);
Giving the following:
Look at the doc page to see all the options available to modify/customize your text. Notice that you don't have to use sprintf to generate the string, however the newline character (\n) must be used inside sprintf in order to work.
EDIT In response to your comment below, if you need to save the image with text embedded in it you can use getframe to get the content of the figure and then imwrite to save it:
hFrame = getframe(gca) %// Get content of figure
imwrite(hFrame.cdata,'MyImage.tif','tif') %// Save the actual data, contained in the cdata property of hFrame
EDIT #2 As alternatives to using getframe, look here as there are 2 nice ideas proposed, i.e. using saveas or avi files.
The answer above (Benoit_11) requires that you display the image first, write the text, then save the image. This becomes very slow if you are processing the frames of a video (not a single image, or a few of them). To get a much faster processing time, you have to write directly to the image matrix. One alternative I can think of (but that is not very elegant) is to create (or download) small templates for the alphabet characters (e.g. 20x20), then overwrite the image matrix in the required region with those templates. For example, for an RGB "true color" image, we'll have something like this:
im(y:y+19,x:x+19,:)=template;

VL_SLIC MATLAB Output for VL_FEAT

I am using the VL_SLIC function in MATLAB and I am following the tutorial for the function here: http://www.vlfeat.org/overview/slic.html
This is the code I have written so far:
im = imread('slic_image.jpg');
regionSize = 10 ;
regularizer = 10;
vl_setup;
segments = vl_slic(single(im), regionSize, regularizer);
imshow(segments);
I just get a black image and I am not able to see the segmented image with the superpixels. Is there a way that I can view the result as shown in the webpage?
The reason why is because segments is actually a map that tells you which regions of your image are superpixels. If a pixel in this map belongs to ID k, this means that this pixel belongs to superpixel k. Also, the map is of type uint32 and so when you try doing imshow(segments); it really doesn't show anything meaningful. For that image that is seen on the website, there are 1023 segments given your selected parameters. As such, the map spans from 0 to 1023. If want to see what the segments look like, you could do imshow(segments,[]);. What this will do is that the region with the ID of 1023 will get mapped to white, while the pixels that don't belong to any superpixel region (ID of 0), gets mapped to black. You would actually get something like this:
Not very meaningful! Now, to get what you see on the webpage, you're going to have to do a bit more work. From what I know, VLFeat doesn't have built-in functionality that shows you the results like what is seen on their webpage. As such, you will have to write code to do it yourself. You can do this by following these steps:
Create a map that is true that is the same size as the image
For each superpixel region k:
Create another map that marks true for any pixel belonging to the region k, and false otherwise.
Find the perimeter of this region.
Set these perimeter pixels to false in the map created in Step #1
Repeat Step #2 until we have finished going through all of the regions.
Use this map to mask out all of the pixels in the original image to get what you see in the website.
Let's go through that code now. Below is the setup that you have established:
vl_setup;
im = imread('slic_image.jpg');
regionSize = 10 ;
regularizer = 10 ;
segments = vl_slic(single(im), regionSize, regularizer);
Now let's go through that algorithm that I just mentioned:
perim = true(size(im,1), size(im,2));
for k = 1 : max(segments(:))
regionK = segments == k;
perimK = bwperim(regionK, 8);
perim(perimK) = false;
end
perim = uint8(cat(3,perim,perim,perim));
finalImage = im .* perim;
imshow(finalImage);
We thus get:
Bear in mind that this is not exactly the same as what you get on the website. I simply went to the website and saved that image, then proceeded with the code I just showed you. This is probably because the slic_image.jpg image is not the exact original that was given in their example. There seems to be superpixels in areas where there are some bad quantization artifacts. Also, I'm using a relatively old version of VLFeat - Version 0.9.16. There may have been improvements to the algorithm since then, so I may not be using the most up to date version. In any case, this is something for you that you can start with.
Hope this helps!
I found these lines in vl_demo_slic.m may be useful.
segments = vl_slic(im, regionSize, regularizer, 'verbose') ;
% overaly segmentation
[sx,sy]=vl_grad(double(segments), 'type', 'forward') ;
s = find(sx | sy) ;
imp = im ;
imp([s s+numel(im(:,:,1)) s+2*numel(im(:,:,1))]) = 0 ;
It generates edges from the gradient of the superpixel map (segments).
While I want to take nothing away from ~ rayryeng's ~ beautiful answer.
This could also help.
http://www.vlfeat.org/matlab/demo/vl_demo_slic.html
Available in: toolbox/demo

removing units from plot

I try to remove the Matlab-given units from this plot but I don't find a way:
figure(1)
hold on
set(gcf,'PaperUnits','centimeters',...
'PaperSize',[15 9],...
'PaperPosition',[0 0 15 9]);
pzmap(LB); sgrid; grid on; axis equal;
title('');
xlabel('\sigma [rad/s]')
ylabel('\omega [rad/s]')
hold off
After that commands the xlabel looks like this: \sigma [rad/s] (seconds^-1). The seconds comes with pzmap. How can I remove them?
I found, some strange behavour:
If generate code by the figure plot manager I get this:
% Create xlabel
xlabel('\sigma [rad/s] (seconds^{-1})','Units','pixels');
Why???
Now I get it - without pzmap/pzplot
pol = pole(sys)
figure(1)
plot(real(pol(:)),imag(pol(:)),'x')
title('');
xlabel('\sigma [rad/s]');
ylabel('\omega [rad/s]');
sgrid
pzmap is a high-level convenience function, but it's not the best choice for this (it's also stored in a folder of obsolete functions in R2013a, so it may get marked for official removal in the future). Instead, let's create an example plot using pzplot directly instead of pzmap. This is still a plot function that does a lot under the hood, but it returns a handle, h, to the plot:
sys = rss(3,2,2);
h = pzplot(sys);
sgrid;
axis equal;
We can via the options of a pzplot with getoptions:
p = getoptions(h)
To set the labels and units as you desire, you might try this, using setoptions:
p.Title.String = '';
p.XLabel.String = '\sigma';
p.YLabel.String = '\omega';
setoptions(h,p);
I believe that the units of 'seconds-1' that the plot displays is equivalent to the 'rad/s' that you want to specify. I know that the two look is very different (I prefer being specific about radians myself), but that's a disadvantage of using such a plot function that tries to do everything for you. If you wanted to remove the default string or add another option, you'd likely have to do some low level hacking. An easier way around, might be to use the "Generate Code..." command ("Generate M-File..." in older versions") under the "File" menu in the figure's toolbar and edit the plot labels there (there's also a programmatic option for this on the File Exchange). Or you could output to postscript and edit that.
Alternatively, you can use pzoptions to create a list of options to pass to pzplot or pzmap (undocumented in the latter case):
p = pzoptions;
p.Title.String = '';
p.XLabel.String = '\sigma';
p.YLabel.String = '\omega';
sys = rss(3,2,2);
pzplot(sys,p);
sgrid;
axis equal;
You'll see that that for some reason the text size is much smaller in this case. pzplot and pzmap must set the font size to 10 themselves. You could easily do this.
Fore more on customizing this and related Control toolbox plots, see this article.
After intense low-level digging, there is actually a pretty simple way to override the default behavior.
p = pzplot(sys);
p.AxesGrid.XUnits = 'rad/s';
p.AxesGrid.YUnits = 'rad/s';
Changes appear to take effect immediately. I have even tried setting the value to nothing, i.e.
p.AxesGrid.XUnits = '';
and it effectively removes the annoying parenthesis with the units. Technically, matlab creates a custom-class element they store under the name AxesGrid in the resppack.mpzplot class instance, with some standard LTI-behavior. You can probably work around some stuff by "injecting" a script with the same name as one of the standard library functions, so that it will be called instead, and change things in there, but this is the closest I have come to removing those annoying units in a few lines.
As a side info, the AxesGrid object is initialized in
...\controllib\graphics\#resppack\#pzplot\initialize.m
should you want to check it out.

How do I detect an instance of an object in an image?

I have an image containing several specific objects. I would like to detect the positions of those objects in this image. To do that I have some model images containing the objects I would like to detect. These images are well cropped around the object instance I want to detect.
Here is an example:
In this big image,
I would like to detect the object represented in this model image:
Since you originally posted this as a 'gimme-da-codez' question, showing absolutely no effort, I'm not going to give you the code. I will describe the approach in general terms, with hints along the way and it's up to you to figure out the exact code to do it.
Firstly, if you have a template, a larger image, and you want to find instances of that template in the image, always think of cross-correlation. The theory is the same whether you're processing 1D signals (called a matched filter in signal processing) or 2D images.
Cross-correlating an image with a known template gives you a peak wherever the template is an exact match. Look up the function normxcorr2 and understand the example in the documentation.
Once you find the peak, you'll have to account for the offset from the actual location in the original image. The offset is related to the fact that cross-correlating an N point signal with an M point signal results in an N + M -1 point output. This should be clear once you read up on cross-correlation, but you should also look at the example in the doc I mentioned above to get an idea.
Once you do these two, then the rest is trivial and just involves cosmetic dressing up of your result. Here's my result after detecting the object following the above.
Here's a few code hints to get you going. Fill in the rest wherever I have ...
%#read & convert the image
imgCol = imread('http://i.stack.imgur.com/tbnV9.jpg');
imgGray = rgb2gray(img);
obj = rgb2gray(imread('http://i.stack.imgur.com/GkYii.jpg'));
%# cross-correlate and find the offset
corr = normxcorr2(...);
[~,indx] = max(abs(corr(:))); %# Modify for multiple instances (generalize)
[yPeak, xPeak] = ind2sub(...);
corrOffset = [yPeak - ..., xPeak - ...];
%# create a mask
mask = zeros(size(...));
mask(...) = 1;
mask = imdilate(mask,ones(size(...)));
%# plot the above result
h1 = imshow(imgGray);
set(h1,'AlphaData',0.4)
hold on
h2 = imshow(imgCol);
set(h2,'AlphaData',mask)
Here is the answer that I was about to post when the question was closed. I guess it's similar to yoda's answer.
You can try to use normalized cross corelation:
im=rgb2gray(imread('di-5Y01.jpg'));
imObj=rgb2gray(imread('di-FNMJ.jpg'));
score = normxcorr2(imObj,im);
imagesc(score)
The result is: (As you can see, the whitest point corresponds to the position of your object.)
The Mathworks has a classic demo of image registration using the same technique as in #yoda's answer:
Registering an Image Using Normalized Cross-Correlation