Scramble the pixels of black and white images in Matlab - matlab

I have a series of black and white images (not greyscale, black and white; 2D matrices in Matlab), and I need to randomly scramble the pixels. I found this package in Mathworks File Exchange (https://it.mathworks.com/matlabcentral/fileexchange/66472-image-shuffle); one of the functions, imScrambleRand, does exactly what I need, but it works for RGB images (3D matrices). Is there a way to transform b&w images into 3D matrices so that I can use that function? Or can anyone suggest any other script that does what I need? Keep in mind that I'm not familiar with Matlab, but I'll do my best.
Thank you.
EDIT 1: When I import the BW image I get a 2D matrix of logic values (0 = black, 1 = white). I think the different data format (logic vs integer) is what yields errors when using the function for RGB images.
EDIT 2: I adapted the demo code from the aforementioned package and I used the suggestion by #Jonathan for transforming a 2D matrix into a 3D matrix, and added a loop to transform the logic values into RGB integer values, then use the imScrambleRand function. It works, but what I obtain is the following image: SCRAMBLED IMAGE. This is the BW picture I start with: BW IMAGE. So I checked the scrambled image, and the function from the FEX file actually scrambles within the RGB values, meaning that I found, for instance, a pixel with RGB 0,255,0. So I solved a problem but actually there's a problem within the function: it doesn't scramble pixels, it scrambles values generating colors that were not in the original picture.
EDIT 3: I used the code provided by #nhowe and I obtain exactly what I need, thanks!
EDIT 4: Ok, turns out it's not ok to scramble the pixels since it makes the image too scattered and different from the starting image (you don't say?), but I need to scramble BLOCKS OF PIXELS so that you can't really recognize the image but the black pixels are not too scattered. Is there a way to do that using the code provided by #nhowe?
EDIT 5: It should be ok with this function: https://it.mathworks.com/matlabcentral/fileexchange/56160-hio-been-hb-imagescramble

A simple way to scramble matrix M:
r = rand(size(M));
[~,ri] = sort(r(:));
M(ri) = M;

The simplest solution to go from grayscale to RGB might be this:
rgbImage = cat(3, grayImage, grayImage, grayImage);
Then apply your function from FEX and extract one color channel, assuming that the FEX function will yield three identical color channels.

Related

MATLAB imshow for 3D color image

I have a medical imaging matrix of size [200x200x200].
In order to display it, I am currently using imshow3D function, which is an excellent tool, built by Maysam Shahedi.
This tool displays the 3D image slice by slice, with mouse based slice browsing
In my current project, I generate an RGB image for each z-layer from the original input image. The output is a 3D color image of size [200x200x200x3] (each layer is now represented by 3 channels).
The imshow3D function works great on grayscale images. Is it possible to use it to display RGB images?
I took a look at this nice imshow3D function from Matlab FileExchange, and it is quite straight-forward to change it to allow working with a stack of RGB images.
The magic part of the function is
imshow(Img(:,:,S))
which displays the slice S of the image Img. We can simply change it to show all 3 channels of image S by changing this to Img(:,:,S,:). The result will be of size 200-by-200-by-1-by-3, while MATLAB expects RGB images to be of size 200-by-200-by-3. Simply squeeze this image to get the correct dimension. This results in:
imshow(squeeze(Img(:,:,S,:))
So to show RGB images, do a search-and-replace inside the function imshow3D, to replace all occurrences of Img(:,:,S) with squeeze(Img(:,:,S,:)) and it works!

How to represent points from PCA space in the RGB space

I'm trying to implement a morphological method for image colors from the article: "Probabilistic pseudo-morphology for grayscale and color images". At one point, we compute the PCA on the entire image, calculate a chebyschev inequality ( the equation 11 in the paper: http://perso.telecom-paristech.fr/~bloch/P6Image/Projets/pseudoMorphology/Caliman-PR2014.pdf) of each 3 components which gives us 3 pairs of vector. We next have to represent these vectors back in the RGB space. I don't understand how do we do that? Can someone help me?
Looking at the paper, I'm not sure which representation you're talking about. I'm guessing Fig. 16, but I'm not sure. There's a note in the caption of Fig. 16 that's helpful: "(For interpretation of the references to color in this figure caption, the reader is referred to the web version of this article.)"
Possible answer: if you have a matrix of size A = (y_pixels,x_pixels,3), then you can display this as an RGB image via:
A = rand(100,100,3);
figure()
imshow(A)
Note that your matrix must be scaled in the range [0..1].
It seems easy to map your your PCA scores for each pixel onto such a matrix, and simply display that as RGB via imshow. Does that solve your problem?

Manually turn RGB image into Grayscale Matlab

Let me preface this by saying, I understand there are functions that would do this for me, but I wanted to do it manually so I could understand what exactly is happening here.
So my goal is to read in a RGB image and turn it into a grayscale. All of my image processing work up to this point has been solely grayscale based, so I am a little bit lost.
I have tried to first read in the image by doing
fid = fopen('color.raw');
myimage = imread(fid, [512 384], 'uint8');
fclose(fid);
but myimage ends up as an empty 0 x 0 matrix. I think I need to assign an "R" "G" and "B" value to each pixel, thus giving each pixel three values for the three colors, but I am not sure if thats correct, and even how to attempt that.
my question is the following: How would I read in a RGB image and then turn into a grayscale one.
EDIT: So I understand how I would go about turning the RGB into the grayscale after getting the R G and B values, but I cannot seem to make Matlab read in the image, can anyone offer any assistance? using imread seems to make the most sense, but
[pathname] = ...
uigetfile({'*.raw';'*.mdl';'*.mat';'*.*'},'File Selector');
fid = fopen(pathname);
myimage = imread(fid);
fclose(fid);
Is not working, im getting an error of invalid filename for fopen, and I really do not understand why.
Conceptually you just average the red, green, and blue components and then providing that average as the output for the red, green, and blue components. You can do this using a simple arithmetic mean
(r+g+b)/3.
Or for kicks, you can use a geometric mean to get a slightly different contrast..
(r*g*b)^(1/3).
imread - read image from graphics file (it's in the documentation)
http://www.mathworks.com/help/matlab/ref/imread.html
For RGB to gray scale use the luminosity method. http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
The luminosity method is a more sophisticated version of the average
method. It also averages the values, but it forms a weighted average
to account for human perception. We’re more sensitive to green than
other colors, so green is weighted most heavily. The formula for
luminosity is 0.21 R + 0.71 G + 0.07 B.
The problem with averaging all 3 values as other users have indicated is that that is not how our eyes work at all.
When you average your images, you get the result below (on the built in peppers.png image)
You are effectively doing grayImg=.33*R+.33*G+.33*B when you find the average, now compare that to how MATLAB calculates grayscale values (with consideration into how humans view images)
0.2989 * R + 0.5870 * G + 0.1140 * B
See the stark contrast in values?
To get better looking data, stay closer to the coefficients MATLAB uses :)
The way MATLAB renders it is like this:

Smoothing matlab plot figures

I have obtained the following figure using a 120x120 matrix and the surf function.
Is there a simple way to make the lines between different colors look smoother?
First of all, surf may not be the best way to display 2D-image - if you don't actually need the height information, imagesc will work just fine. Even better, it won't show the differently colored lines between hexagons, since it's not going through the colormap at intersections.
However, regardless of your approach, a low-resolution bitmap will not be automatically transformed into a "arbitrary"-resolution vector graphics - and you may not want that, anyway, if you use the figure to allow you to inspect at which combination of (x,y) you obtained at a given value.
There are three approaches to make your image prettier - (1) segment the hexagons, and use patch to create a vector-graphics image. (2) upsample the image with imresample. (3) create a RGB image and smoothen each color separately to get softer transitions:
%# assume img is your image
nColors = length(unique(img));
%# transform the image to rgb
rgb = ind2rgb((img+fliplr(img)),jet(nColors)); %# there are much better colormaps than jet
%# filter each color
for i=1:3,rgbf(:,:,i)=imfilter(rgb(:,:,i),fspecial('gaussian',9,3),'replicate');end

MATLAB. Inverse crop images.

I would like to crop an image but I want to retain the part of image that is outside of the rectangle. How can this can be done?
It seems that with imcrop only the part within the rectangle can be retained.
An image in Matlab is represented by a matrix, just like any other matrix, you can read more about representation forms here.
It seems that what you want to do is to take the area that you don't want and change the values of the corresponding cells in the matrix to the color that you want to put instead (each cell in the matrix is a pixel in the image). That is if you know the place where your unwanted data is.
If you don't know where it is, and want to use the tool given by imcrop to manually choose the "cropped" area, you can take the resulting matrix, and find the part of the original image which is an exact match with the cropped part, and to color it as you wish.
The code for doing this:
I=imread('img_9.tif');
I2=imcrop(I,[60,50,85,85]);
n_big=size(I);
n_small=size(I2);
for j1=1:(n_big(1)-n_small(1))
for j2=1:(n_big(2)-n_small(2))
Itest=I(j1:j1+n_small(1)-1,j2:j2+n_small(2)-1,:);
if ( Itest == I2)
I(j1:j1+n_small(1)-1,j2:j2+n_small(2)-1,:) = zeros(n_small(1),n_small(2),3);
end
end
end
figure(1);
imshow(I);
figure(2);
imshow(I2);
The results of my test were:
original:
cropped:
resulting image:
maybe what you want to do is first a mask with the inverse area of what you want to crop and save this result.