Displaying pixel values of an image in Octave? - image

If I load and display an image, for example
c = imread('cameraman.tif');
imshow(c)
then in the plot window, under the image itself, there are two numbers indicating the current cursor position, in the form
[39.25, 120.6]
I have two questions about this:
Can the display be tweaked so that the positions are integers? So one image pixel per screen pixel?
Can this information include the grayscale/rgb value of the pixel, such as
[23, 46] = 127
or
[23, 46] = (46,128,210)?
I've tried fiddling with the "axis" command, but I haven't found anything which helps.
I guess what I want is something like Matlab's "Pixel Information Tool" impixelinfo:
http://www.mathworks.com.au/help/images/ref/impixelinfo.html though I know from the octave image wiki at http://wiki.octave.org/Image_package that impixelinfo is not currently implemented in Octave. But maybe there's another way to achieve the same result?
I'm using Octave-3.8.0, the image package 2.2.0, under linux (Ubuntu 12.04).

GNU Octave 3.8 uses FLTK as standard graphics_toolkit. Unfortunately WindowButtonMotionFcn is only triggered if a button is pressed while the mouse moves (dragging) with this toolkit (Today I would consider this as a bug). But you can use WindowButtonDownFcn.
This examples updates the title with the position and the image value at that position if you click in the image:
img = imread ("cameraman.png");
imshow (img)
function btn_down (obj, evt)
cp = get (gca, 'CurrentPoint');
x = round (cp(1, 1));
y = round (cp(1, 2));
img = get (findobj (gca, "type", "image"), "cdata");
img_v = NA;
if (x > 0 && y > 0 && x <= columns (img) && y <= rows (img))
img_v = squeeze (img(y, x, :));
endif
if (numel (img_v) == 3) # rgb image
title(gca, sprintf ("(%i, %i) = %i, %i, %i", x, y, img_v(1), img_v(2), img_v(3)));
elseif (numel (img_v) == 1) # gray image
title(gca, sprintf ("(%i, %i) = %i", x, y, img_v));
endif
endfunction
set (gcf, 'WindowButtonDownFcn', #btn_down);
You can also place a text next to the cursor if you want.

Related

Plot over an image background in MATLAB

I'd like to plot a graph over an image. I followed this tutorial to Plot over an image background in MATLAB and it works fine:
% replace with an image of your choice
img = imread('myimage.png');
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
% make data to plot - just a line.
x = min_x:max_x;
y = (6/8)*x;
imagesc([min_x max_x], [min_y max_y], img);
hold on;
plot(x,y,'b-*','linewidth',1.5);
But when I apply the procedure to my study case, it doesn't work. I'd like to do something like:
I = imread('img_png.png'); % here I load the image
DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000);
% with the last 3 lines I calculated the stream network on a geographic area using the TopoToolBox
imagesc(I);
hold on
plot(S)
The aim is to plot the stream network over the satellite image of the same area.
The only difference between the two examples that doesn't let the code working is in the plot line, in the first case "plot(x,y)" works, in the other one "plot(S)" doesn't.
Thanks guys.
This is the satellite image, imagesc(I)
It is possible that the plot method of the STREAMobj performs it's own custom plotting including creating new figures, axes, toggling hold states, etc. Because you can't easily control what their plot routine does, it's likely easier to flip the order of your plotting so that you plot your stuff after the toolbox plots the STREAMobj. This way you have completely control over how your image is added.
% Plot the STREAMobj
hlines = plot(S);
% Make sure we plot on the same axes
hax = ancestor(hlines, 'axes');
% Make sure that we can add more plot objects
hold(hax, 'on')
% Plot your image data on the same axes
imagesc(I, 'Parent', hax)
Maybe I am preaching to the choir or overlooking something here but the example you used actually mapped the image to the data range of the plot, hence the lines:
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
imagesc([min_x max_x], [min_y max_y], img);
where you directly plot your image
imagesc(I);
If now your data coordinates and your image coordinates are vastly different you either see one or the other.
Thanks guys, I solved in this way:
I = imread('orto.png'); % satellite image loading
DEM = GRIDobj('demF1.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000); % Stream network extraction
x = S.x; % [node attribute] x-coordinate vector
y = S.y; % [node attribute] y-coordinate vector
min_x = min(x);
max_x = max(x);
min_y = min(y);
max_y = max(y);
imagesc([min_x max_x], [min_y max_y], I);
hold on
plot(S);
Here's the resulting image: stream network over the satellite image
Actually the stream network doesn't match the satellite image just because I'm temporarily using different images and DEM.

To show/join Two Images Simultaneously in Matlab's slider?

I cannot make too big file (like tried here) so I need to show only portions at a time.
However, I cannot make the transfer from one file to another smooth in Matlab.
I am trying to expand the solution of the thread To refresh imshow in Matlab? for two images. The problem is the ending of image A and start of the image B. Now, I have an interruption in the flow, which I do not like because I cannot show two images at the same time without an interruption.
In the example here, it is not needed to filter the axes.
Code
iterationCounter=1;
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
while(iterationCounter < 7)
filenamePng=fullfile(homedir, '/Images/Raw/', iterationCounter, '.png');
imgRGB=imread(filenamePng);
% https://stackoverflow.com/a/29952648/54964
%%// create sliding-window video
len = 40*2^3;
signal = imgRGB(:,1:end,:);
hImg = imshow(signal(:,1:1+len,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k=1:M-len
set(hImg, 'CData',signal(:,k:k+len,:))
writeVideo(vid, getframe());
end
iterationCounter=iterationCounter+1;
end
close(vid);
Output for Image A and Image B
where there is an interruption in the slider after each image.
The picture is just a screenshot of two images: beginning and ending of the slider. The blue area is just OS X GUI but still indicates that there is a gap and interruption between the start and end.
How can show/join two images simultaneously in Matlab's slider?
In order to display multiple images side by side in this scrolling window, I think the easiest approach is to actually load all of the images upfront into an array that is [nRows x (nColumns * nImages) x 3] and then just use the original code to scroll through this.
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
signal = [];
% Load all the images into one "long" image
for k = 1:7
filename = fullfile(homedir, sprintf('%d.png', k));
img = imread(filename);
signal = cat(2, signal, img);
end
%%// create sliding-window video
windowWidth = 320; % Width in pixels
hImg = imshow(signal(:,1:1 + windowWidth,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k = 1:(M - windowWidth)
set(hImg, 'CData',signal(:,k:k + windowWidth,:))
writeVideo(vid, getframe());
end
close(vid);
The command imagesc is a low-level image command where Suever's proposal does not work.
A general approach to remove padding/margins/background is to use
<plot imshow imagesc ...>
set(gca,'position',[0 0 1 1],'units','normalized')

Need to crop thousands of images / sprites while preserving midpoint

I have thousands of character sprites (though, really they're just PNG files with transparency) which were saved out from Maya.
These are character animations, with almost all of them being 12 frames each. Each animation is rendered from each of the 8 cardinal directions.
In each animation, the character is already centered in the frame (this is how it's exported from Maya); however, each image has a bunch of white/transparent space around it.
I need to batch crop these sprites horizontally from the outside -> in order to preserve the character's midpoint in the frame. The reason for this is if it's not preserved, as the game swaps from one animation to the next, the character would appear to move or jump around. So, it's important the character is horizontally centered (using the midpoint of their body) in the frame across all their animations.
Additionally... ideally the character is always at or very near the bottom edge of the sprite.
For the coup de grace... the final cropped image needs to be an even number, or divisible by 2, for game engine reasons.
Is there any way to at least partially, or entirely, automate this? Or are there any programs that someone could recommend to help with the automation of this; free or paid.
I dunno yet if a Python-based answer suits your but here is what I got, with a bit of work your can copy and paste this script to your script editor in Maya or execute it in your Python interpreter.
This script requires the PIL library to be installed.
To install it on Maya, you can follow this link Mistermatti's blog. Unzip the file and paste the PIL folder in your maya install here: Maya20XX\Python\Lib\site-packages
This works on Maya2014, havn't tested on other versions tho.
from PIL import Image
import time
start_time = time.time()
#parses the image to find the first pixel on the x axis which is not blank
def parseXImage(pixelMap, resWidth, resHeight):
for x in range(0, int(resWidth/2)):
for y in range(0, int(resHeight/2)):
if (pixelMap[x,y] != (0, 0, 0, 0)) or \
(pixelMap[x,resHeight-y-1] != (0, 0, 0, 0)) or \
(pixelMap[resWidth-x-1,y] != (0, 0, 0, 0)) or \
(pixelMap[resWidth-x-1,resHeight-y-1] != (0, 0, 0, 0)):
return x
return None
#parses the image to find the first pixel on the y axis which is not blank
def parseYImage(pixelMap, resWidth, resHeight):
topFound = False
bottomFound = False
yTop = None
yBottom = None
for y in range(0, int(resHeight/2)):
for x in range(0, int(resWidth/2)):
if not topFound:
if (pixelMap[x,y] != (0, 0, 0, 0)) or \
(pixelMap[resWidth-x-1,y] != (0, 0, 0, 0)):
yTop = y
topFound = True
if not bottomFound:
if (pixelMap[x,resHeight-y-1] != (0, 0, 0, 0)) or \
(pixelMap[resWidth-x-1,resHeight-y-1] != (0, 0, 0, 0)):
yBottom = y
bottomFound = True
return yTop, yBottom
imageList = [r"Path\To\Image\Mod_Turn.001.png",
r"Path\To\Image\Mod_Turn.002.png",
r"Path\To\Image\Mod_Turn.003.png",
r"Path\To\Image\Mod_Turn.004.png",
r"Path\To\Image\Mod_Turn.005.png"]
#get images resolution
imagePil = Image.open(imageList[0])
resWidth, resHeight = imagePil.size #get the resolution of the first image in the list
imagePil.close()
valueWidthList = []
valueHeightTopList = []
valueHeightBottomList = []
for imageListIndex, imagePath in enumerate(imageList):
imagePil = Image.open(imagePath)
pixelMap = imagePil.load()
xValue = parseXImage(pixelMap, resWidth, resHeight) #now parse the image to find x
yTopValue, yBottomValue = parseYImage(pixelMap, resWidth, resHeight) #now parse the image to find y
valueWidthList.append(xValue) #Store it
valueHeightTopList.append(yTopValue) #Store it
valueHeightBottomList.append(yBottomValue) #Store it
imagePil.close()
xValueToCrop = min(valueWidthList) #Get the minimal value of X crop among all the entries
yTopValueToCrop = min(valueHeightTopList) #Get the minimal value of Y crop among all the entries
yBottomValueToCrop = min(valueHeightBottomList) #Get the minimal value of Y crop among all the entries
#This is the crop square we will use
cropSquare = (xValueToCrop, yTopValueToCrop, resWidth-xValueToCrop, resHeight-yBottomValueToCrop )
for imagePath in imageList:
imagePil = Image.open(imagePath)
#Replace Turn by something in the name of your image
imagePil.crop(cropSquare).save(imagePath.replace("Turn", "Turn_Cropped")) #Crop dans save the image
imagePil.close()
print("--- %s seconds ---" % (time.time() - start_time))
You need to change the imageList dict with your own paths to images and "Turn", "Turn_Cropped" at the very end of the script.
FYI, processing 300 images #720p took about 250 seconds. This can be improved.
Perhaps give TexturePacker a try https://www.codeandweb.com/texturepacker
I've used it before when dealing with sprites and find it quite nice. I believe it also has command-line functionality, though I haven't used it myself. And it's cross-platform.

Mid line through a set of dicom images in matlab

I have a set of Dicom images on matlab and i would like to add a midline going through all the images
I am outputting the images via imshow3d function
thanks
Edit: here's what i have, the random points are not in the middle they just run through the image
>> clc;
>>clear;
>>%imports dicom images
>>run DicomImport.m;
>>%random points for shortest distance test
>>a = [1 10 200];
>>b = [500 512 300];
>>ab = b - a;
>>n = max(abs(ab)) + 1;
>>s = repmat(linspace(0, 1, n)', 1, 3);
>>for d = 1:3
>> s(:, d) = s(:, d) * ab(d) + a(d);
>>end
>>s = round(s);
>>Z = 593;
>>N = 512;
>>X = zeros(N, N, Z);
>>X(sub2ind(size(X), s(:, 1), s(:, 2), s(:, 3))) = 1;
>>C = find(X);
>>ans.Img(C) = 5000;
>> %shows image
>>imshow3D(ans.Img);
So it looks like ans.Img contains the 3D matrix consisting of your image stack. It looks like you've got something going, but allow me to do this a bit differently. Basically, you need to generate a set of coordinates where we can access the image stack and draw a vertical line in the middle of the each image in the image stack. Do something like this. First get the dimensions of the stack, then determine the halfway point for the columns. Next, generate a set of coordinates that will draw a line down the middle for one image. After you do this, repeat this for the rest of the slices and get the column major indices for these:
%// Get dimensions
[rows,cols,slices] = size(ans.Img);
%// Get halfway point for columns
col_half = floor(cols/2);
%// Generate coordinates for vertical line for one slice
coords_middle_row = (1:rows).';
coords_middle_col = repmat(col_half, rows, 1);
%// Generate column major indices for the rest of the slices:
ind = sub2ind(size(ans.Img), repmat(coords_middle_row, slices, 1), ...
repmat(coords_middle_col, slices, 1), ...
reshape(kron(1:slices, ones(rows, 1)), [], 1));
%// Set the pixels accordingly
ans.Img(ind) = 5000;
This code is quite similar to the answer I provided to one of your earlier question; i.e. I don't use imshow3D but the framework is similar and simpler to modify in order to suit your need. In this case, upon pressing a pushbutton a line appears at the middle of the stack and you can scroll through it with the slider. I hope this can be of help.
function LineDicom(~)
clc
clear
close all
%// Load demo data
S = load('mri');
%// Get dimensions and number of slices.
ImageHeight = S.siz(1); %// Not used here
ImageWidth = S.siz(2); %// Not used here
NumSlices = S.siz(3);
S.D = squeeze(S.D);
%// Create GUI
hFig = figure('Position',[100 100 400 400],'Units','normalized');
%// create axes with handle
handles.axes1 = axes('Position', [0.2 0.2 0.6 0.6]);
%// create y slider with handle
handles.y_slider = uicontrol('style', 'Slider', 'Min', 1, 'Max', NumSlices, 'Value',1, 'Units','normalized','position', [0.08 0.2 0.08 0.6], 'callback', #(s,e) UpdateY);
handles.SlideryListener = addlistener(handles.y_slider,'Value','PostSet',#(s,e) YListenerCallBack);
%// Create pusbutton to draw line
handles.DrawLineButton= uicontrol('style', 'push','position', [40 40 100 30],'String','Draw line', 'callback', {#DrawLine,handles});
%// Flag to know whether pushbutton has been pushed
handles.LineDrawn = false;
%// Show 1st slice
imshow(S.D(:,:,1))
guidata(hFig,handles);
%// Listeners callbacks followed by sliders callbacks. Used to display each
%// slice smoothly.
function YListenerCallBack
handles = guidata(hFig);
%// Get current slice
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
%// If button was button, draw line
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
function UpdateY(~)
handles = guidata(hFig); %// Get handles.
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
%// Pushbutton callback to draw line.
function DrawLine(~,~,handles)
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
handles.LineDrawn = true;
guidata(hFig,handles);
end
end
Sample output:
and after moving the slider up:
Is this what you meant? If not I'll remove that answer haha and sorry.

how to browse image and process it before it's displayed to axes in GUI matlab

I want to create a GUI with matlab, to browse for an image and process it before displaying it to some axes.
I can't browse the image with my current program, and the image that I want to display is related to the previous process. Is it possible to browse and display all of the processed images to the axes with just one pushbutton? Can someone help me create the GUI for this sample program?
folder = 'D:\wildlife';
baseFileName = 'page-6.png';
fullFileName = fullfile(folder, baseFileName);
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
% Didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %Gambar tidak ditemukan.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
rgbImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = .
[rows columns numberOfColorBands] = size(rgbImage);
% Display the original color image.
subplot(2, 3, 1);
imshow(rgbImage);
title('Gambar Asli', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
%set the morphology
SE = strel ('square', 3);
j=imerode (rgbImage, SE);
subplot(2, 3, 2);
imshow(j);
title('Penebalan Citra', 'FontSize', fontSize);
% Binarize to find black pixels
% Find where either red, green, or blue channel is dark.
thresholdValue = 55;
binaryImage = j(:,:, 1) < thresholdValue | j(:,:, 2) < thresholdValue | j(:,:, 3) < thresholdValue;
% Display the image.
subplot(2, 3, 3);
imshow(binaryImage);
title('Citra Biner', 'FontSize', fontSize);
% Fill the image
filledImage = imfill(binaryImage, 'holes');
% Display the image.
subplot(2, 3, 4);
imshow(filledImage);
title('Pengisian Citra Biner', 'FontSize', fontSize);
drawnow;
To create the GUI, Matlab's GUIDE feature is well documented and relatively easy to use and learn (http://www.mathworks.com/help/matlab/gui-building-basics.html). Simply type 'guide' at the Matlab prompt to bring up the quick start menu.
Once you create a new blank GUI, you can add a push button and as many axes as you need to display the various images (4 for your sample code above). Then the code to browse for, process, and display the image can be placed in the callback for the push button. To open the callback code, right click on the push button and select "View Callbacks -> Callback" from the menu.
Then you can us something like the following to browse for the desired image:
[baseFileName, folder, FilterIndex] = uigetfile('*.png');
To display the image in the desired axis, specify the appropriate axis handle as the 'Parent' argument in your calls to 'imshow', rather than using 'subplot':
% Display the original color image.
fullFileName = [folder baseFileName];
rgbImage = imread(fullFileName);
imshow(rgbImage, 'Parent', handles.axes1);

Resources