what I am trying to do is calculate the temperature of a selected area in an image
my code:
M=imread('IR003609.BMP');
a = min(M(:)); % find the minimum temperature in the image
b = max(M(:)); % find the maximum temperature in the image
imshow(M,[a b]);
h = roipoly();
maskOfROI =h;
selectedValues = M(maskOfROI);
averageTemperature =mean(selectedValues)
maxTemperature = max(selectedValues)
minTemperature = min(selectedValues)
my image is this with the mouth area selected
enter image description here
Then the values that he throws at me are these:
averageTemperature =
64.0393
maxTemperature =
uint8
255
minTemperature =
uint8
1
Now my questions are, is the program throwing the correct temperature values (comparing the values seen in the image)? or what values are emissivity?
if they are wrong values how could I solve it?
please help
I see that the color bar is the hue of HSV so I suggest you convert to temperature along these lines: you convert to HSV, use the first layer, then rescale to fit 31-39 deg. And the colors seem to be flipped, so flip them upside down.
M = imread('jQLo5.jpg');
Mhsv = rgb2hsv(M);
maxTemp = 39;
minTemp = 31;
Mtemp = (1-Mhsv(:,:,1))*(maxTemp-minTemp)+minTemp;
figure;
imagesc(Mtemp)
colormap(flipud(hsv))
colorbar
Related
I am new to MATLAB Image Processing and currently I have two images - one is a grayscale image of my object and the second is the scaled image generated from MATLAB using imagesc function. I am trying to overlay this scaled image on top of my grayscale image to get a spatial resolution for easier observation. Attached are the two images:
A) Grayscale Image:
B) Scaled Image:
There were a few difficulties that I encountered. Firstly, the scaled image is not saved in the same pixel dimensions, but I can get around that using the imwrite function:
im = imagesc(ScaledDiff);
imwrite(get(im,'cdata'),'scaleddiff.tif')
However, doing so will result in a loss of colorbar and the colormap. Secondly, even if I manage to shrink the scaled image to the size of the grayscale image, overlaying it is still a challenge. Ideally, I would like to set the transparency (or 'alpha') to 0 for those pixels with < 0.02 in scaled image value.
Any idea on how to do this will be greatly appreciated! Sorry if I was unclear!
UPDATE:
Thanks to Rotem, I have managed to overlay the grayscale image and a particular region of my heatmap:
However, I need to display the colorbar corresponding to the heatmap values, because otherwise the information is lost and the overlay will be useless. How should I do this? Below is a snippet of my code, where ScaledIntDiff contains the values from 0 to 0.25 that is displayed on the heatmap:
Brightfield = imread('gray.jpg'); % read background image
I1 = ind2rgb(gray2ind(Brightfield), gray); % convert indices into RGB scale
scale = 1000;
ScaledIntDiff2 = round(ScaledIntDiff.*scale);
I2 = ind2rgb(ScaledIntDiff2, jet(256)); % this is for the heatmap
threshold = 0.02;
I2R = I2(:,:,1); I2G = I2(:,:,2); I2B = I2(:,:,3);
I1R = I1(:,:,1); I1G = I1(:,:,2); I1B = I1(:,:,3);
% Replace pixels in I2 with pixels in I1 if the value of ScaledIntDiff of those pixels is below the threshold
I2R(ScaledIntDiff<threshold) = I1R([ScaledIntDiff<threshold]);
I2G(ScaledIntDiff<threshold) = I1G([ScaledIntDiff<threshold]);
I2B(ScaledIntDiff<threshold) = I1B([ScaledIntDiff<threshold]);
I2(:,:,1) = I2R; I2(:,:,2) = I2G; I2(:,:,3) = I2B;
figure
imshow(I2)
I know that the code above is highly inefficient, so suggestions on how to improve it will be very welcomed. Thank you!
Check the following:
I = imread('CKbi2Ll.jpg'); %Load input.
%Convert I to true color RGB image (all pixels R=G=B are gray color).
I1 = ind2rgb(I, gray(256));
%Convert I to true color RGB image with color map parula (instead of using imagesc)
I2 = ind2rgb(I, parula(256));
%Set the transparency (or 'alpha') to 0 for those pixels with < 0.02 in scaled image value.
%Instead of setting transparency, replace pixels with values from I1.
threshold = 0.02; %Set threshold to 0.02
I2(I1 < threshold) = I1(I1 < threshold);
%Blend I1 and I2 into J.
alpha = 0.3; %Take 0.3 from I2 and 0.7 from I1.
J = I2*alpha + I1*(1-alpha);
%Display output
imshow(J);
Adding a colorbar with ticks labels from 0 to 0.25:
Set color map to parula - it doesn't affect the displayed image, because image format is true color RGB.
Crate array of add 6 ticks from 0 to 250.
Create cell array of 6 TickLabels from 0 to 0.25.
Add colorbar with Ticks and TickLabels properties created earlier.
Add the following code after imshow(J);:
colormap(parula(256));
TLabels = cellstr(num2str((linspace(0, 0.25, 6))'));
T = linspace(1, 250, 6);
colorbar('Ticks', T', 'TickLabels', TLabels);
imshow('ClmypzU.jpg');
colormap(jet(256));
TLabels = cellstr(num2str((linspace(0, 0.25, 6))'));
T = linspace(1, 250, 6);
colorbar('Ticks', T', 'TickLabels', TLabels);
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.
I have a sample image and a target image. I want to transfer the color shades of sample image to target image. Please tell me how to extract the color from sample image.
Here the images:
input source image:
input map for desired output image
output image
You can use a technique called "Histogram matching" (another description)
Basically, you use the histogram for your source image as a goal and transform the values for each input map pixel to get the output histogram as close to source as possible. You do it for each rgb channel of the image.
Here is my python code for that:
from scipy.misc import imsave, imread
import numpy as np
imsrc = imread("source.jpg")
imtint = imread("tint_target.jpg")
nbr_bins=255
imres = imsrc.copy()
for d in range(3):
imhist,bins = np.histogram(imsrc[:,:,d].flatten(),nbr_bins,normed=True)
tinthist,bins = np.histogram(imtint[:,:,d].flatten(),nbr_bins,normed=True)
cdfsrc = imhist.cumsum() #cumulative distribution function
cdfsrc = (255 * cdfsrc / cdfsrc[-1]).astype(np.uint8) #normalize
cdftint = tinthist.cumsum() #cumulative distribution function
cdftint = (255 * cdftint / cdftint[-1]).astype(np.uint8) #normalize
im2 = np.interp(imsrc[:,:,d].flatten(),bins[:-1],cdfsrc)
im3 = np.interp(imsrc[:,:,d].flatten(),cdftint, bins[:-1])
imres[:,:,d] = im3.reshape((imsrc.shape[0],imsrc.shape[1] ))
imsave("histnormresult.jpg", imres)
The output for you samples will look like that:
You could also try making the same in HSV colorspace - it might give better results.
I think the hardest part is to determine the dominant color of the first image. Just looking at it, with all the highlights and shadows, the best overall color will be the one that has the highest combination of brightness and saturation. I start with a blurred image to reduce the effects of noise and other anomalies, then convert each pixel to the HSV color space for the brightness and saturation measurement. Here's how it looks in Python with PIL and colorsys:
blurred = im1.filter(ImageFilter.BLUR)
ld = blurred.load()
max_hsv = (0, 0, 0)
for y in range(blurred.size[1]):
for x in range(blurred.size[0]):
r, g, b = tuple(c / 255. for c in ld[x, y])
h, s, v = colorsys.rgb_to_hsv(r, g, b)
if s + v > max_hsv[1] + max_hsv[2]:
max_hsv = h, s, v
r, g, b = tuple(int(c * 255) for c in colorsys.hsv_to_rgb(*max_hsv))
For your image I get a color of (210, 61, 74) which looks like:
From that point it's just a matter of transferring the hue and saturation to the other image.
The histogram matching solutions above did not work for me. Here is my own, based on OpenCV:
def match_image_histograms(image, reference):
chans1 = cv2.split(image)
chans2 = cv2.split(reference)
new_chans = []
for ch1, ch2 in zip(chans1, chans2):
hist1 = cv2.calcHist([ch1], [0], None, [256], [0, 256])
hist1 /= hist1.sum()
hist2 = cv2.calcHist([ch2], [0], None, [256], [0, 256])
hist2 /= hist2.sum()
lut = np.searchsorted(hist1.cumsum(), hist2.cumsum())
new_chans.append(cv2.LUT(ch1, lut))
return cv2.merge(new_chans).astype('uint8')
obtain average color from color map
ignore saturated white/black colors
convert light map to grayscale
change dynamic range of lightmap to match your desired output
I use max dynamic range. You could compute the range of color map and set it for light map
multiply the light map by avg color
This is how it looks like:
And this is the C++ source code
//picture pic0,pic1,pic2;
// pic0 - source color
// pic1 - source light map
// pic2 - output
int x,y,rr,gg,bb,i,i0,i1;
double r,g,b,a;
// init output as source light map in grayscale i=r+g+b
pic2=pic1;
pic2.rgb2i();
// change light map dynamic range to maximum
i0=pic2.p[0][0].dd; // min
i1=pic2.p[0][0].dd; // max
for (y=0;y<pic2.ys;y++)
for (x=0;x<pic2.xs;x++)
{
i=pic2.p[y][x].dd;
if (i0>i) i0=i;
if (i1<i) i1=i;
}
for (y=0;y<pic2.ys;y++)
for (x=0;x<pic2.xs;x++)
{
i=pic2.p[y][x].dd;
i=(i-i0)*767/(i1-i0);
pic2.p[y][x].dd=i;
}
// extract average color from color map (normalized to unit vecotr)
for (r=0.0,g=0.0,b=0.0,y=0;y<pic0.ys;y++)
for (x=0;x<pic0.xs;x++)
{
rr=BYTE(pic0.p[y][x].db[picture::_r]);
gg=BYTE(pic0.p[y][x].db[picture::_g]);
bb=BYTE(pic0.p[y][x].db[picture::_b]);
i=rr+gg+bb;
if (i<400) // ignore saturated colors (whiteish) 3*255=white
if (i>16) // ignore too dark colors (whiteish) 0=black
{
r+=rr;
g+=gg;
b+=bb;
}
}
a=1.0/sqrt((r*r)+(g*g)+(b*b)); r*=a; g*=a; b*=a;
// recolor output
for (y=0;y<pic2.ys;y++)
for (x=0;x<pic2.xs;x++)
{
a=DWORD(pic2.p[y][x].dd);
rr=r*a; if (rr>255) rr=255; pic2.p[y][x].db[picture::_r]=BYTE(rr);
gg=g*a; if (gg>255) gg=255; pic2.p[y][x].db[picture::_g]=BYTE(gg);
bb=b*a; if (bb>255) bb=255; pic2.p[y][x].db[picture::_b]=BYTE(bb);
}
I am using own picture class so here some members:
xs,ys size of image in pixels
p[y][x].dd is pixel at (x,y) position as 32 bit integer type
p[y][x].db[4] is pixel access by color bands (r,g,b,a)
[notes]
If this does not meet your needs then please specify more and add more images. Because your current example is really not self explanatonary
Regarding previous answer, one thing to be careful with:
once the CDF will reach its maximum (=1), the interpolation will get mislead and will match wrongly your values. To avoid this, you should provide the interpolation function only the part of CDF meaningful (not after where it reaches 1) and the corresponding bins. Here the answer adapted:
from scipy.misc import imsave, imread
import numpy as np
imsrc = imread("source.jpg")
imtint = imread("tint_target.jpg")
nbr_bins=255
imres = imsrc.copy()
for d in range(3):
imhist,bins = np.histogram(imsrc[:,:,d].flatten(),nbr_bins,normed=True)
tinthist,bins = np.histogram(imtint[:,:,d].flatten(),nbr_bins,normed=True)
cdfsrc = imhist.cumsum() #cumulative distribution function
cdfsrc = (255 * cdfsrc / cdfsrc[-1]).astype(np.uint8) #normalize
cdftint = tinthist.cumsum() #cumulative distribution function
cdftint = (255 * cdftint / cdftint[-1]).astype(np.uint8) #normalize
im2 = np.interp(imsrc[:,:,d].flatten(),bins[:-1],cdfsrc)
if (cdftint==1).sum()>0:
idx_max = np.where(cdftint==1)[0][0]
im3 = np.interp(im2,cdftint[:idx_max+1], bins[:idx_max+1])
else:
im3 = np.interp(im2,cdftint, bins[:-1])
Enjoy!
im1 = grayscale images
im2 = im2bw(im1, graythresh)
Can I superimpose im1 and im2 to get a 3rd image with the features from im1 and im2 according to a specified interval of graylevel ?
For example, I choose an interval of gray level between 110 and 120. All the pixel from im1 which have a value between 110 and 120 will keep their initial gray value and all the other one will keep their binary value (from im2).
I'm new to matlab.
Thank you.
Do you really need to threshold using im2bw?
If not, I would recommend something like this (using your example threshold values):
im1(im1<110) = 0;
im1(im1>120) = 255;
Every value below 110 will be set to zero, every value above 120 will be set to 255 (maximum gray level) and the rest remains uneffected.
I hope this is your wanted result. You do not need to superimpose images.
If you really want to use im2bw (uses a more advanced threshold method) and superimpose the images im1 and im2 you can go with this:
im1(im1<110 | im1>120) = 0;
im2(im1>=110 & im1<=120) = 0;
im3 = im1 + im2uint8(im2);
This isn't tough to do in Matlab, see this example:
range = [90 150];
grayThresh = 115;
im1 = imread('rice.png');
im2 = (im1 > grayThresh) * 255;
im3 = im1;
binaryPlaces = im1 < range(1) | im1 > range(2);
im3(binaryPlaces) = im2(binaryPlaces);
imshow(im3);
The hardest part is keeping track of what data type each of your images are. If the image is a double, then 0 is black and 1 is white, but if the image is a uint8, then 0 is black and 255 is white. Because the test image rice.png (included with Matlab) loads as a uint8, we need multiply to im2 by 255.
I need to determine the amount/quality of color in an image in order to compare it with other images and recommend a user (owner of the image) maybe he needs to print it in black and white and not in color.
So far I'm analyzing the image and extracting some data of it:
The number of different colors I find in the image
The percentage of color in the whole page (color pixels / total pixels)
For further analysis I may need other characteristic of these images. Do you know what else is important (or I'm missing here) in image analysis?
After some time I found a missing characteristic (very important) which helped me a lot with the analysis of the images. I don't know if there is a name for that but I called it the average color of the image:
When I was looping over all the pixels of the image and counting each color I also retrieved the information of the RGB values and summarized all the Reds, Greens and Blues of all the pixels. Just to come up with this average color which, again, saved my life when I wanted to compare some kind of images.
The code is something like this:
File f = new File("image.jpg");
BufferedImage im = ImageIO.read(f);
int tot = 0;
int red = 0;
int blue= 0;
int green = 0;
int w = im.getWidth();
int h = im.getHeight();
// Going over all the pixels
for (int i=0;i<w;i++){
for (int j=0;j<h;j++){
int pix = im.getRGB(i, j); //
if (!sameARGB(pix)) { // Compares the RGB values
tot+=1;
red+=pix.getRed();
green+=pix.getGreen();
blue+=pix.getBlue();
}
}
}
And you should get the results like this:
// Percentage of color on the image
double per = (double)tot/(h*w);
// Average color <-------------
Color c = new Color((double)red/tot,(double)green/tot,(double)blue/tot);