Concatenate RGB channels with a loop 'for' - image

I have R,G,B image channels of an image and I want to concatenate them to get the colored image using a for loop. Is it possible?
I tried something like below but it gives me an error:
for i=1:3
image=cat(3,img(:,:,i)
end
I already know how to do it without a loop using the command cat : image=cat(3,imgR,imgG,imgB)

I don't see a point in using a loop here... it's very inefficient... especially if you know how many images you want to stack together. The call to cat as you have alluded to in your post at the very end is more than sufficient.
however, if you want to get this working, you have to specify at least two matrices that you want to use to concatenate together to create a new matrix when using cat in order to perform concatenation. You are only specifying one matrix and if you do this, the output will simply be just the channel itself and if you use this code, you will only extract out the blue channel (the last channel).
If you want to retain the concatenations made for each channel, do this instead:
for ii = 1 : 3
image = cat(3, image, img(:,:,ii));
end
This will take the pre-existing variable image and concatenate your matrix with each slice in img and update the variable image.

Related

how to save more than one image in matlab using imwrite?

I have 3 parameters, each parameter give one output image, now I put one loop for the parameters and I want to have 3 output images in each loop and save it, How can I do that using imwrite ?
Thanks a lot
I didn't understand your question as clearly as expected but are you looking for something like this:
for i=1:3
parameter=functionGivingParamater(input_argument);%%I guess paramter is the image format
imwrite(strcat('imageNo_'+num2str(i)),parameter);
end

MATLAB ConnectedComponentLabeler does not work in for loop

I am trying to get a set of binary images' eccentricity and solidity values using the regionprops function. I obtain the label matrix using the vision.ConnectedComponentLabeler function.
This is the code I have so far:
files = getFiles('images');
ecc = zeros(length(files)); %eccentricity values
sol = zeros(length(files)); %solidity values
ccl = vision.ConnectedComponentLabeler;
for i=1:length(files)
I = imread(files{i});
[L NUM] = step(ccl, I);
for j=1:NUM
L = changem(L==j, 1, j); %*
end
stats = regionprops(L, 'all');
ecc(i) = stats.Eccentricity;
sol(i) = stats.Solidity;
end
However, when I run this, I get an error says indicating the line marked with *:
Error using ConnectedComponentLabeler/step
Variable-size input signals are not supported when the OutputDataType property is set to 'Automatic'.'
I do not understand what MATLAB is talking about and I do not have any idea about how to get rid of it.
Edit
I have returned back to bwlabel function and have no problems now.
The error is a bit hard to understand, but I can explain what exactly it means. When you use the CVST Connected Components Labeller, it assumes that all of your images that you're going to use with the function are all the same size. That error happens because it looks like the images aren't... hence the notion about "Variable-size input signals".
The "Automatic" property means that the output data type of the images are automatic, meaning that you don't have to worry about whether the data type of the output is uint8, uint16, etc. If you want to remove this error, you need to manually set the output data type of the images produced by this labeller, or the OutputDataType property to be static. Hopefully, the images in the directory you're reading are all the same data type, so override this field to be a data type that this function accepts. The available types are uint8, uint16 and uint32. Therefore, assuming your images were uint8 for example, do this before you run your loop:
ccl = vision.ConnectedComponentLabeler;
ccl.OutputDataType = 'uint8';
Now run your code, and it should work. Bear in mind that the input needs to be logical for this to have any meaningful output.
Minor comment
Why are you using the CVST Connected Component Labeller when the Image Processing Toolbox bwlabel function works exactly the same way? As you are using regionprops, you have access to the Image Processing Toolbox, so this should be available to you. It's much simpler to use and requires no setup: http://www.mathworks.com/help/images/ref/bwlabel.html

Creating animation with multiple plots in Octave

I'm using Octave to write a script that plots a function at different time periods. I was hoping to create an animation of the plots in order to see the changes through time.
Is there a way to save each plot for each time point, so that all plots can be combined to create this animation?
It's a bit of kludge, but you can do the following (works here with octave 4.0.0-rc2):
x = (-5:.1:5);
for p = 1:5
plot (x, x.^p)
print animation.pdf -append
endfor
im = imread ("animation.pdf", "Index", "all");
imwrite (im, "animation.gif", "DelayTime", .5)
Basically, print all your plots into a pdf, one per page. Then read the pdf's as images and print them back as gifs. This will not work on Matlab (its imread implementation can't handle pdf).
This creates an animated gif
data=rand(100,100,20); %100 by 100 and 20 frames
%data go from 0 to 1, so lets convert to 8 bit unsigned integers for saving
data=data*2^8;
data=uint8(data);
%Write the first frame to a file named animGif.gif
imwrite(data(:,:,1),'/tmp/animGif.gif','gif','writemode','overwrite',...
'LoopCount',inf,'DelayTime',0);
%Loop through and write the rest of the frames
for ii=2:size(data,3)
imwrite(data(:,:,ii),'/tmp/animGif.gif','gif','writemode','append','DelayTime',0)
end
Had to come chime in here because this was the top Google result for me when I was looking for help with this. I had issues with both answers, and some other issues, too. Notably:
For Rick T's answer, the code snippet doesn't write a plot figure, it just writes matrix data. Getting the plot window was a pain.
For carandraug's answer, writing to a PDF took a very long time and made a gigantic PDF.
On my own machine, I'm pretty sure I used apt-install to get Octave, but the getframe function I found referenced in other answers wasn't found. Turns out I had installed version 4.4, which was from 2018 (>3 years old).
I removed the old version of Octave sudo apt remove octave, then installed the new version with snap. If you try octave from a terminal without it installed it should prompt you to the snap install - be sure to include the # 6.4.0 or whatever is included in the command.
Once I had the current version installed, I got access to the getframe command, which is what lets you convert directly from a figure handle to image data - this bypasses the hackey (but previously necessary step) in #carandraug's answer where you had to write to PDF or some other image as a placeholder.
I used #RickT's answer to make my own MakeGif function, which I will share with you all here. Note that MakeGif stores the filename in a persistent variable, meaning it is retained across calls. If you change the filename it will make (or overwrite!!) the new file. If you need to overwrite the current file (i.e., running the same script multiple times and want new results) then you can use clear MakeGif between calls and that will reset the persistentFilename.
Here is the code for the MakeGif function; code to test it with is provided after this:
function MakeGif(figHandle, filename)
persistent persistentFilename = [];
if isempty(filename)
error('Can''t have an empty filename!');
endif
if ~ishandle(figHandle)
error('Call MakeGif(figHandle, filename); no valid figHandle was passed!');
endif
writeMode = 'Append';
if isempty(persistentFilename)|(filename!=persistentFilename)
persistentFilename = filename;
writeMode = 'Overwrite';
endif
imstruct = getframe(figHandle);
imwrite(imstruct.cdata, filename, 'gif', 'WriteMode',writeMode,'DelayTime',0);
endfunction
And here is the code to test the function. There's a commented-out call to clear MakeGif between the blue and green colors. If you leave it commented out it will append the green sine wave to the blue sine wave, resulting in alternating colors after every cycle - again the filename is persistent in the function. If you uncomment that call then the MakeGif function will treat the green's call as "new" and trigger the overwrite of the blue sine wave and all you'll see is green.
clear all;
time = 0:0.1:2*pi;
nSamples = numel(time);
figHandle = figure(1);
for i=1:nSamples
plot(time,sin(time + time(i)),'Color','blue');
drawnow;
MakeGif(figHandle, 'test.gif');
endfor
% Uncomment the 'clear' command below to clear the MakeGif persistent
% memory, which will trigger the green sine wave to overwrite the blue.
% Default behavior is to APPEND a green sine wave because the filename
% is the same.
%clear MakeGif;
for i=1:nSamples
plot(time,sin(time + time(i)),'Color','green');
drawnow;
MakeGif(figHandle, 'test.gif');
endfor
I spent several hours on this after being super dissatisfied with laggy screen captures so I really hope this helps someone in the future! Good luck and best wishes from the Age of Covid lol.
#Chuck thanks for that code; I've been using it to save 1500-frame GIFs of simulation output, and I find that after maybe ~500 frames the time to save the next frame to the output during the call to MakeGif starts to become ... unnerving. I guess imwrite reads and writes the entirety of the output file at each call that includes the 'WriteMode','Append' pair. At frame 1500 my output is 480Mb so that becomes untenable.
An apparent rescue for this is hinted at in the doc for Octave 7.1.0's imwrite, with the suggestion that you can pass it a 4-dimensional array and write the entire image sequence with one call. I haven't been able to make this work, though: Calling imwrite that way seems to simply write the very first image in the sequence into every frame in the output file.

Caffe Multiple Input Images

I'm looking at implementing a Caffe CNN which accepts two input images and a label (later perhaps other data) and was wondering if anyone was aware of the correct syntax in the prototxt file for doing this? Is it simply an IMAGE_DATA layer with additional tops? Or should I use separate IMAGE_DATA layers for each?
Thanks,
James
Edit: I have been using the HDF5_DATA layer lately for this and it is definitely the way to go.
HDF5 is a key value store, where each key is a string, and each value is a multi-dimensional array. Thus, to use the HDF5_DATA layer, just add a new key for each top you want to use, and set the value for that key to store the image you want to use. Writing these HDF5 files from python is easy:
import h5py
import numpy as np
filelist = []
for i in range(100):
image1 = get_some_image(i)
image2 = get_another_image(i)
filename = '/tmp/my_hdf5%d.h5' % i
with hypy.File(filename, 'w') as f:
f['data1'] = np.transpose(image1, (2, 0, 1))
f['data2'] = np.transpose(image2, (2, 0, 1))
filelist.append(filename)
with open('/tmp/filelist.txt', 'w') as f:
for filename in filelist:
f.write(filename + '\n')
Then simply set the source of the HDF5_DATA param to be '/tmp/filelist.txt', and set the tops to be "data1" and "data2".
I'm leaving the original response below:
====================================================
There are two good ways of doing this. The easiest is probably to use two separate IMAGE_DATA layers, one with the first image and label, and a second with the second image. Caffe retrieves images from LMDB or LEVELDB, which are key value stores, and assuming you create your two databases with corresponding images having the same integer id key, Caffe will in fact load the images correctly, and you can proceed to construct your net with the data/labels of both layers.
The problem with this approach is that having two data layers is not really very satisfying, and it doesn't scale very well if you want to do more advanced things like having non-integer labels for things like bounding boxes, etc. If you're prepared to make a time investment in this, you can do a better job by modifying the tools/convert_imageset.cpp file to stack images or other data across channels. For example you could create a datum with 6 channels - the first 3 for your first image's RGB, and the second 3 for your second image's RGB. After reading this in using the IMAGE_DATA layer, you can split the stream into two images using a SLICE layer with a slice_point at index 3 along the slice_dim = 1 dimension. If further down the road, you decide that you want to load even more complex assortments of data, you'll understand the encoding scheme and can write your own decoding layer based off of src/caffe/layers/data_layer.cpp to gain full control of the pipeline.
You may also consider using HDF5_DATA layer with multiple "top"s

Matlab image processing

I have a folder which contains images (100) from the experiment that I did. I also have another folder which contains the background images (100 also) from the detector.
I have written a code that does something like this:
% Define images directory
% Define detector bg directory
% Loop over each frame and do some processing
for a=1:length(image directory)
%read files from directory
bg_corrected_image = frame#-bg_image# % # begins with 1
n=size(image directory)
new_images=zeros(n)
% Now sort through each pixel in bg_corrected image and assign value according to a criterion
for ii=1:size(bg_corrected_image,1)
jj=1:size(bg_corrected_image,2)
pixel=bg_corrected_image(ii,jj);
if pixel>500
pix_mod=0;
elseif pixel<30
pix_mod=0;
else
pix_mod=pixel;
end
new_image(ii,jj)=pix_mod;
end
******************* CODE TO SAVE IMAGE AND NOT OVERWRITE AFTER EACH
ITERATION OF LOOP?
end
What I want to do now is to save each image(frame) after it had gone through the pixel sorting regimen so that I can just sum them all after the loop has ended. I am not too sure what is the best way to do it? I think what I need to do is to create a cell array which saves a "new_image" after each iteration and the code for that should go where I put asteriks. Please note I don't want to save images earlier in my code. Any help much appreciated.
Maybe something like the below - load in all your images to a 3D matrix "imagestack", then process them all, then output them all. Note the vectorization on the pixel replacement here will be much faster than your for-loop iteration over the pixels.
IMAGECOUNT=100;
FILEPATH_IN='images/input/%d.jpg';
FILEPATH_OUT='images/output/%d.jpg';
I=imread(sprintf(FILEPATH,1));
[hei wid]=size(I);
imagestack=zeros(hei,wid,100);
for n=1:IMAGECOUNT
imagestack(:,:,n)=imread(sprintf(FILEPATH_IN,n));
end
imagestack(imagestack>500)=0;
imagestack(imagestack<30)=0;
for n=1:IMAGECOUNT
imwrite(imagestack(:,:,n),sprintf(FILEPATH_OUT,n));
end

Resources