Plot sparse matrix in matlab - image

I want to plot a sparse matrix in an imagesc type of style (one color for each pixel, and not symbols a la scatter). The matrix consists of blobs that are spread ut over a 10000x10000 square. I expect about 100 blobs and each blob being 50x100 pixels. This matrix is so big that it becomes very laggy to zoom in or out or to move around in it to inspect the data. And I still want to keep the resolution. Is there any way to plot a sparse matrix which just plots the blobs and has the "zero-color" of the colormap as a background that does not take any space in memory?
Lets say we have a matrix M that looks like this:
[1, 2, 1, 0;
0, 1, .4, 0;
0, 0, 0, 0;
0, 7, 0, 0]
When I plot it as a sparse matrix
figure;
imagesc(sparse(M));
It takes the same size as omitting the sparse-command. This is what I want to circumvent.

Instead of treating the matrix as an image, you could plot only its nonzero values. Using scatter (instead of plot) allows you to have color as a function of value, as in imagesc.
By default scatter leaves the background white, so you have to adjust that. This is done in two steps: make sure scatter's color scaling assigns the first color of your colormap to value 0; and then manually set the axis' background to that color.
I haven't tested if this takes up less memory, though.
%// Generate example matrix
M = 10000*rand(1000);
M(M>100) = 0;
M = sparse(M); %// example 1000x1000 matrix with ~1% sparsity
%// Do the plot
cmap = jet; %// choose a colormap
s = .5; %// dot size
colormap(cmap); %// use it
[ii, jj, Mnnz] = find(M); %// get nonzero values and its positions
scatter(1,1,s,0) %// make sure the first color corresponds to 0 value.
hold on
scatter(ii,jj,s,Mnnz); %// do the actual plot of the nonzero values
set(gca,'color',cmap(1,:)) %// set axis backgroud to first color
colorbar %// show colorbar
Note axes' orientation may be different from imagesc.

Related

Image Repetition from Binary to Cartesian

I'd like to take in an RGB image, find the points in the image that are white, and get the cartesian coordinates of those points in the image. I've gotten most of the way there, but when I try to plot the cartesian coordinates, I get a vertically tiled image (i.e. 5 overlapped copies of what I should see). Anyone know what could be causing this?
,
Code: (JPG comes in as 2448 x x3264 x 3 uint8)
I = imread('IMG_0245.JPG');
imshow(I); % display unaltered image
% Convert image to grayscale
I = rgb2gray(I);
% Convert image to binary (black/white)
I = im2bw(I, 0.9);
% Generate cartesian coordinates of image
imageSize = size(I);
[x, y] = meshgrid( 1:imageSize(1), 1:imageSize(2) );
PerspectiveImage = [x(:), y(:), I(:)];
% Get indices of white points only
whiteIndices = find(PerspectiveImage(:,3));
figure; plot( PerspectiveImage(whiteIndices, 1), PerspectiveImage(whiteIndices, 2),'.');
% Flip vertically to correct indexing vs. plotting issue
axis ij
Very simple. You're declaring your meshgrid wrong. It should be:
[x, y] = meshgrid( 1:imageSize(2), 1:imageSize(1) );
The first parameter denotes the horizontal extents of the 2D grid, and so you want to make this vary for as many columns as you have. Similarly, the second parameter denotes the vertical extents of the 2D grid, and so you want to make this for as many rows as you have.
I had to pre-process some of your image to get some good results because your original image had a large white border surrounding the image. I had to remove this border by removing all pure white pixels. I also read in the image directly from StackOverflow:
I = imread('http://s7.postimg.org/ovb53w4ff/Track_example.jpg');
mask = all(I == 255, 3);
I = bsxfun(#times, I, uint8(~mask));
This was the image I get after doing my pre-processing:
Once I do this and change your meshgrid call, I get this:

access and change the values of the R, G and B of a desired pixel in an image using MATLAB

How can I change the values of the R, G and B in an image manually using MATLAB?
The computation for a green color enhancement needs to be done so how do we access and change the values of RGB using MATLAB?
Assuming you are using imread to read in the image, an RGB image is stored as an M x N x 3 matrix, where M,N are the rows and columns of the image. This is essentially a 3D matrix, where each colour plane is in a particular dimension. The red plane is the first of the third dimensions, the green plane is the second, and the blue plane is the third. As such, you can do something like:
im = imread('onion.png'); % // Built-in to MATLAB
red = im(:,:,1); %// Red channel
green = im(:,:,2); % // Green channel
blue = im(:,:,3); % // Blue channel
You can also merge the planes back by doing: im2 = cat(3, red, green, blue); Now, you can manipulate any of these planes by themselves. If you want to grab a subset of the image, you can do:
imSubset = im(row1:row2, col1:col2, :);
This will grab all pixels between rows row1 to row2 and columns col1 to col2. You can then split up the image into their corresponding planes.
Now, if you want to manually change pixels, you simply access whichever rows and columns you want in each of the planes and set them to whatever you want. For example, if you wanted to set a particular region in your image to all yellow pixels, you can do this:
im(1:50,1:50,1) = 0;
im(1:50,1:50,2) = 255;
im(1:50,1:50,3) = 255;
imshow(im);
This should place a yellow square of 50 pixels wide in the top left corner. You can also do the subset approach by:
imSubset = im(1:50,1:50,:); %// Extract
imSubset(:,:,1) = 0; %// Set
imSubset(:,:,2) = 255;
imSubset(:,:,3) = 255;
im(1:50,1:50,:) = imSubset; %// Place back
If I can be a shameless promoter, take a look at my Introduction to Digital Image Processing using MATLAB slides - http://www.slideshare.net/rayryeng1/introduction-to-digital-image-processing-using-matlab
Good luck!

converting rgb image to double and keeping the values in matlab

I have an image and I want to import this image to matlab. I am using the following code. The problem that I have is that when I convert the image to grayscale, everything will be changed and the converted image is not similar to original one. In another words, I want to keep the values (or let say the image) as it is in the original image. Is there any way for doing this?
I = imread('myimage.png');
figure, imagesc(I), axis equal tight xy
I2 = rgb2gray(I);
figure, imagesc(I2), axis equal tight xy
Your original image is already using a jet colormap. The problem is, when you convert it to grayscale, you lose some crucial information. See the image below.
In the original image you have a heatmap. Blue areas generally indicate "low value", whereas red areas indicate "high values". But when converted to grayscale, both areas indicate low value, as they aproach dark pixels (see the arrows).
A possible solution is this:
You take every pixel of your image, find the nearest (closest)
color value in the jet colormap and use its index as a gray value.
I will show you first the final code and the results. The explanation goes below:
I = im2double(imread('myimage.png'));
map = jet(256);
Irgb = reshape(I, size(I, 1) * size(I, 2), 3);
Igray = zeros(size(I, 1), size(I, 2), 'uint8');
for ii = 1:size(Irgb, 1)
[~, idx] = min(sum((bsxfun(#minus, Irgb(ii, :), map)) .^ 2, 2));
Igray(ii) = idx - 1;
end
clear Irgb;
subplot(2,1,1), imagesc(I), axis equal tight xy
subplot(2,1,2), imagesc(Igray), axis equal tight xy
Result:
>> whos I Igray
Name Size Bytes Class Attributes
I 110x339x3 894960 double
Igray 110x339 37290 uint8
Explanation:
First, you get the jet colormap, like this:
map = jet(256);
It will return a 256x3 colormap with the possible colors on the jet palette, where each row is a RGB pixel. map(1,:) would be kind of a dark blue, and map(256,:) would be kind of a dark red, as expected.
Then, you do this:
Irgb = reshape(I, size(I, 1) * size(I, 2), 3);
... to turn your 110x339x3 image into a 37290x3 matrix, where each row is a RGB pixel.
Now, for each pixel, you take the Euclidean distance of that pixel to the map pixels. You take the index of the nearest one and use it as a gray value. The minus one (-1) is because the index is in the range 1..256, but a gray value is in the range 0..255.
Note: the Euclidean distance takes a square root at the end, but since we are just trying to find the closest value, there is no need to do so.
EDIT:
Here is a 10x faster version of the code:
I = im2double(imread('myimage.png'));
map = jet(256);
[C, ~, IC] = unique(reshape(I, size(I, 1) * size(I, 2), 3), 'rows');
equiv = zeros(size(C, 1), 1, 'uint8');
for ii = 1:numel(equiv)
[~, idx] = min(sum((bsxfun(#minus, C(ii, :), map)) .^ 2, 2));
equiv(ii) = idx - 1;
end
Irgb = reshape(equiv(IC), size(I, 1), size(I, 2));
Irgb = Irgb(end:-1:1,:);
clear equiv C IC;
It runs faster because it exploits the fact that the colors on your image are restricted to the colors in the jet palette. Then, it counts the unique colors and only match them to the palette values. With fewer pixels to match, the algorithm runs much faster. Here are the times:
Before:
Elapsed time is 0.619049 seconds.
After:
Elapsed time is 0.061778 seconds.
In the second image, you're using the default colormap, i.e. jet. If you want grayscale, then try using colormap(gray).

is coordinate mapping same as pixel mapping in matlab for delaunay triangulation

I have to transform pixels from one image onto another image, by feature detection. I have calculated the projective transformation matrix. One image is the base image, and the other is a linearly translated image.
Now I have to define a larger grid and assign pixels from the base image to it. For example, if the base image is 20 at (1,1), on the larger grid I will have 20 at (1,1). and assign zeroes to all the unfilled values of the grid. Then I have to map the linearly translated image onto the base image and write my own algorithm based on "delaunay triangulation" to interpolate between the images.
My question is that when I map the translated image to the base image, I use the concept
(w,z)=inv(T).*(x,y)
A=inv(T).*B
where (w,z) are coordinates of the base image, (x,y) are coordinates of the translated image, A is a matrix containing coordinates (w z 1) and B is matrix containing coordinates (x y 1).
If I use the following code I get the new coordinates, but how do I relate these things to the image? Are my pixels from the second image also translated onto the first image? If not, how can I do this?
close all; clc; clear all;
image1_gray=imread('C:\Users\Javeria Farooq\Desktop\project images\a.pgm');
figure; imshow(image1_gray); axis on; grid on;
title('Base image');
impixelinfo
hold on
image2_gray =imread('C:\Users\Javeria Farooq\Desktop\project images\j.pgm');
figure(2); imshow(image2_gray); axis on; grid on;
title('Unregistered image1');
impixelinfo
% Detect and extract features from both images
points_image1= detectSURFFeatures(image1_gray, 'NumScaleLevels', 100, 'NumOctaves', 5, 'MetricThreshold', 500 );
points_image2 = detectSURFFeatures(image2_gray, 'NumScaleLevels', 100, 'NumOctaves', 12, 'MetricThreshold', 500 );
[features_image1, validPoints_image1] = extractFeatures(image1_gray, points_image1);
[features_image2, validPoints_image2] = extractFeatures(image2_gray, points_image2);
% Match feature vectors
indexPairs = matchFeatures(features_image1, features_image2, 'Prenormalized', true) ;
% Get matching points
matched_pts1 = validPoints_image1(indexPairs(:, 1));
matched_pts2 = validPoints_image2(indexPairs(:, 2));
figure; showMatchedFeatures(image1_gray,image2_gray,matched_pts1,matched_pts2,'montage');
legend('matched points 1','matched points 2');
figure(5); showMatchedFeatures(image1_gray,image3_gray,matched_pts4,matched_pts3,'montage');
legend('matched points 1','matched points 3');
% Compute the transformation matrix using RANSAC
[tform, inlierFramePoints, inlierPanoPoints, status] = estimateGeometricTransform(matched_pts1, matched_pts2, 'projective')
figure(6); showMatchedFeatures(image1_gray,image2_gray,inlierPanoPoints,inlierFramePoints,'montage');
[m n] = size(image1_gray);
image1_gray = double(image1_gray);
[x1g,x2g]=meshgrid(m,n) % A MESH GRID OF 2X2
k=imread('C:\Users\Javeria Farooq\Desktop\project images\a.pgm');
ind = sub2ind( size(k),x1g,x2g);
%[tform1, inlierFramepPoints, inlierPanopPoints, status] = estimateGeometricTransform(matched_pts4, matched_pts3, 'projective')
%figure(7); showMatchedFeatures(image1_gray,image3_gray,inlierPanopPoints,inlierFramepPoints,'montage');
%invtform=invert(tform)
%x=invtform
%[xq,yq]=meshgrid(1:0.5:200.5,1:0.5:200.5);
r=[];
A=[];
k=1;
%i didnot know how to refer to variable tform so i wrote the transformation
%matrix from variable structure tform
T=[0.99814272,-0.0024304502,-1.2932052e-05;2.8876773e-05,0.99930143,1.6285858e-06;0.029063907,67.809265,1]
%lets take i=1:400 so my r=2 and resulting grid is 400x400
for i=1:200
for j=1:200
A=[A; i j 1];
z=A*T;
r=[r;z(k,1)/z(k,3),z(k,2)/z(k,3)];
k=k+1;
end
end
%i have transformed the coordinates but how to assign values??
%r(i,j)=c(i,j)
d1=[];
d2=[];
for l=1:40000
d1=[d1;A(l,1)];
d2=[d2;r(l,1)];
X=[d1 d2];
X=X(:);
end
c1=[];
c2=[];
for l=1:40000
c1=[c1;A(l,2)];
c2=[c2;r(l,2)];
Y=[c1 c2];
Y=Y(:);
end
%this delaunay triangulation is of vertices as far as i understand it
%doesnot have any pixel value of any image
DT=delaunayTriangulation(X,Y);
triplot(DT,X,Y);
I solved this problem by using these two steps:
Use transformPointsForward command to transform the coordinates of image ,using the tform object returned by estimateGeometrcTransform
Use the scatteredInterpolant class in Matlab and use command scatteredInterpolant
to assign the transformed coordinates their respective pixel values.
F=scatteredInterpolant(P,z)
here P=nx2 matrix containing all the transformed coordinates
z=nx1 matrix containing pixel values of image that is transformed,it is obtained by converting image to column vector using image=image(:)
finally all the transformed coordinates are present along with their pixel values on the base image and can be interpolated.
You are doing way too much work here, and I don't think you need the Delaunay Triangulation at all. Use the imwarp function from the Image Processing Toolbox to transform the image. It takes the original image and the tform object returned by estimateGeometricTransform.

How can I "plot" an image on top of another image with a different colormap?

I've got two images, one 100x100 that I want to plot in grayscale and one 20x20 that I want to plot using another colormap. The latter should be superimposed on the former.
This is my current attempt:
A = randn(100);
B = ones(20);
imagesc(A);
colormap(gray);
hold on;
imagesc(B);
colormap(jet);
There are a couple of problems with this:
I can't change the offset of the smaller image. (They always share the upper-left pixel.)
They have the same colormap. (The second colormap changes the color of all pixels.)
The pixel values are normalised over the composite image, so that the first image changes if the second image introduces new extreme values. The scalings for the two images should be separate.
How can I fix this?
I want an effect similar to this, except that my coloured overlay is rectangular and not wibbly:
Just change it so that you pass in a full and proper color matrix for A (i.e. 100x100x3 matrix), rather than letting it decide:
A = rand(100); % Using rand not randn because image doesn't like numbers > 1
A = repmat(A, [1, 1, 3]);
B = rand(20); % Changed to rand to illustrate effect of colormap
imagesc(A);
hold on;
Bimg = imagesc(B);
colormap jet;
To set the position of B's image within its parent axes, you can use its XData and YData properties, which are both set to [1 20] when this code has completed. The first number specifies the coordinate of the leftmost/uppermost point in the image, and the second number the coordinate of the rightmost/lowest point in the image. It will stretch the image if it doesn't match the original size.
Example:
xpos = get(Bimg, 'XData');
xpos = xpos + 20; % shift right a bit
set(Bimg, 'XData', xpos);

Resources