I am reading this paper for enhancing image quality.
my problem is that when I am calculating weighted CDF, I always get 1 as output.
here is the sequence of formulas:
which gamma is defined like this:
which Cw is the weighted CDF:
which I think my main problem would be here.
but to be more clear I will add the rest of the formulas too.
corresponding Weighted Histogram Distribution function is:
and Alpha=C(i) which:
which h_c(i) is clipped histogram , and M is the total intensity levels ( which I'm not sure what is the M, I assumed since sum of Pi should be 1 so it must be sum of the hc_i )
and this is how it is clipping the histogram :
and the clipping limit is calculated with this formula:
here is my code:
sample_img = imread('my image path');
sample_img = im2double(sample_img);
L = 256 % The magnitude of each and every color channel is confined within the range [0 , L-1]
redChannel = sample_img(:,:,1);
greenChannel = sample_img(:,:,2);
blueChannel = sample_img(:,:,3);
max_blue = max(max(blueChannel));
max_green = max(max(greenChannel));
max_red = max(max(redChannel));
min_blue = min(min(blueChannel));
min_green = min(min(greenChannel));
min_red = min(min(redChannel));
bn = blueChannel - min_blue;
rn = redChannel - min_red;
gn = greenChannel - min_green;
max_bn = max(max(bn));
max_rn = max(max(rn));
max_gn = max(max(gn));
b_stretched = bn/max_bn;
r_stretched = rn/max_rn;
g_stretched = gn/max_gn;
% Recombine separate color channels into an RGB image.
rgb_stretched_Image = cat(3, r_stretched, g_stretched, b_stretched);
% Convert RGB to HSI
hsi_image = rgb2hsi(rgb_stretched_Image);
intensity = hsi_image(:, :, 3);
figure()
[counts , binLocations] = imhist(intensity);
imhist(intensity);
hist = counts;
% the clipping limit is computed based on the mean value of the
Tc = mean(hist);
% histogram clipping
length_hist = length(hist);
clipped_hist = zeros(1,length_hist);
for hist_id = 1:length_hist
if hist(hist_id)<Tc
disp('<Tc')
disp(hist(hist_id));
clipped_hist(hist_id) = hist(hist_id);
continue
end
disp('>Tc')
clipped_hist(hist_id) = Tc;
end
% the corresponding PDF (p(i))
% this is where I just used sum(clipped_hist) instead of M
Pi = clipped_hist / sum(clipped_hist);
%CDF
Ci = sum(Pi(1:L));
Alpha = Ci;
%Weighted Histogram Distribution function
Pmin = min(Pi);
Pmax = max(Pi);
Pwi = Pmax * power((Pi-Pmin)/(Pmax-Pmin),Alpha);
%weighted PDF sum
intensity_max = max(max(intensity*L));
Sum_Pwi = sum(Pwi(1:intensity_max));
% weighted CDF
Cwi = sum(Pwi(1:intensity_max)/Sum_Pwi);
%gamma
gamma = 1 - Cwi;
%Transformed pixel intensity
tpi = round(power(intensity/intensity_max,gamma));
since as I said the CDF output is always 1 , the enhanced image is always a white image. and as I see this formula, it must always have 1 as it's output. Am I missing something here ?
and am I right with the M value ?
Related
I'm trying to write an image compression script in MATLAB using multilayer 3D DWT(color image). along the way, I want to apply thresholding on coefficient matrices, both global and local thresholds.
I like to use the formula below to calculate my local threshold:
where sigma is variance and N is the number of elements.
Global thresholding works fine; but my problem is that the calculated local threshold is (most often!) greater than the maximum band coefficient, therefore no thresholding is applied.
Everything else works fine and I get a result too, but I suspect the local threshold is miscalculated. Also, the resulting image is larger than the original!
I'd appreciate any help on the correct way to calculate the local threshold, or if there's a pre-set MATLAB function.
here's an example output:
here's my code:
clear;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% COMPRESSION %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% read base image
% dwt 3/5-L on base images
% quantize coeffs (local/global)
% count zero value-ed coeffs
% calculate mse/psnr
% save and show result
% read images
base = imread('circ.jpg');
fam = 'haar'; % wavelet family
lvl = 3; % wavelet depth
% set to 1 to apply global thr
thr_type = 0;
% global threshold value
gthr = 180;
% convert base to grayscale
%base = rgb2gray(base);
% apply dwt on base image
dc = wavedec3(base, lvl, fam);
% extract coeffs
ll_base = dc.dec{1};
lh_base = dc.dec{2};
hl_base = dc.dec{3};
hh_base = dc.dec{4};
ll_var = var(ll_base, 0);
lh_var = var(lh_base, 0);
hl_var = var(hl_base, 0);
hh_var = var(hh_base, 0);
% count number of elements
ll_n = numel(ll_base);
lh_n = numel(lh_base);
hl_n = numel(hl_base);
hh_n = numel(hh_base);
% find local threshold
ll_t = ll_var * (sqrt(2 * log2(ll_n)));
lh_t = lh_var * (sqrt(2 * log2(lh_n)));
hl_t = hl_var * (sqrt(2 * log2(hl_n)));
hh_t = hh_var * (sqrt(2 * log2(hh_n)));
% global
if thr_type == 1
ll_t = gthr; lh_t = gthr; hl_t = gthr; hh_t = gthr;
end
% count zero values in bands
ll_size = size(ll_base);
lh_size = size(lh_base);
hl_size = size(hl_base);
hh_size = size(hh_base);
% count zero values in new band matrices
ll_zeros = sum(ll_base==0,'all');
lh_zeros = sum(lh_base==0,'all');
hl_zeros = sum(hl_base==0,'all');
hh_zeros = sum(hh_base==0,'all');
% initiate new matrices
ll_new = zeros(ll_size);
lh_new = zeros(lh_size);
hl_new = zeros(lh_size);
hh_new = zeros(lh_size);
% apply thresholding on bands
% if new value < thr => 0
% otherwise, keep the previous value
for id=1:ll_size(1)
for idx=1:ll_size(2)
if ll_base(id,idx) < ll_t
ll_new(id,idx) = 0;
else
ll_new(id,idx) = ll_base(id,idx);
end
end
end
for id=1:lh_size(1)
for idx=1:lh_size(2)
if lh_base(id,idx) < lh_t
lh_new(id,idx) = 0;
else
lh_new(id,idx) = lh_base(id,idx);
end
end
end
for id=1:hl_size(1)
for idx=1:hl_size(2)
if hl_base(id,idx) < hl_t
hl_new(id,idx) = 0;
else
hl_new(id,idx) = hl_base(id,idx);
end
end
end
for id=1:hh_size(1)
for idx=1:hh_size(2)
if hh_base(id,idx) < hh_t
hh_new(id,idx) = 0;
else
hh_new(id,idx) = hh_base(id,idx);
end
end
end
% count zeros of the new matrices
ll_new_size = size(ll_new);
lh_new_size = size(lh_new);
hl_new_size = size(hl_new);
hh_new_size = size(hh_new);
% count number of zeros among new values
ll_new_zeros = sum(ll_new==0,'all');
lh_new_zeros = sum(lh_new==0,'all');
hl_new_zeros = sum(hl_new==0,'all');
hh_new_zeros = sum(hh_new==0,'all');
% set new band matrices
dc.dec{1} = ll_new;
dc.dec{2} = lh_new;
dc.dec{3} = hl_new;
dc.dec{4} = hh_new;
% count how many coeff. were thresholded
ll_zeros_diff = ll_new_zeros - ll_zeros;
lh_zeros_diff = lh_zeros - lh_new_zeros;
hl_zeros_diff = hl_zeros - hl_new_zeros;
hh_zeros_diff = hh_zeros - hh_new_zeros;
% show coeff. matrices vs. thresholded version
figure
colormap(gray);
subplot(2,4,1); imagesc(ll_base); title('LL');
subplot(2,4,2); imagesc(lh_base); title('LH');
subplot(2,4,3); imagesc(hl_base); title('HL');
subplot(2,4,4); imagesc(hh_base); title('HH');
subplot(2,4,5); imagesc(ll_new); title({'LL thr';ll_zeros_diff});
subplot(2,4,6); imagesc(lh_new); title({'LH thr';lh_zeros_diff});
subplot(2,4,7); imagesc(hl_new); title({'HL thr';hl_zeros_diff});
subplot(2,4,8); imagesc(hh_new); title({'HH thr';hh_zeros_diff});
% idwt to reconstruct compressed image
cmp = waverec3(dc);
cmp = uint8(cmp);
% calculate mse/psnr
D = abs(cmp - base) .^2;
mse = sum(D(:))/numel(base);
psnr = 10*log10(255*255/mse);
% show images and mse/psnr
figure
subplot(1,2,1);
imshow(base); title("Original"); axis square;
subplot(1,2,2);
imshow(cmp); colormap(gray); axis square;
msg = strcat("MSE: ", num2str(mse), " | PSNR: ", num2str(psnr));
title({"Compressed";msg});
% save image locally
imwrite(cmp, 'compressed.png');
I solved the question.
the sigma in the local threshold formula is not variance, it's the standard deviation. I applied these steps:
used stdfilt() std2() to find standard deviation of my coeff. matrices (thanks to #Rotem for pointing this out)
used numel() to count the number of elements in coeff. matrices
this is a summary of the process. it's the same for other bands (LH, HL, HH))
[c, s] = wavedec2(image, wname, level); %apply dwt
ll = appcoeff2(c, s, wname); %find LL
ll_std = std2(ll); %find standard deviation
ll_n = numel(ll); %find number of coeffs in LL
ll_t = ll_std * (sqrt(2 * log2(ll_n))); %local the formula
ll_new = ll .* double(ll > ll_t); %thresholding
replace the LL values in c in a for loop
reconstruct by applying IDWT using waverec2
this is a sample output:
The problem statement is - To search over a window of possible displacements (You will search [-10,10] pixels), score each one using some image matching metric, and take the displacement with the best score. The simplest one is the Sum of Squared Differences (SSD) distance, which simply subtracts one image region from the other and evaluates the sum of the squared values in each pixel. You need to do SSD based calculations on image regions which are of double type.
As R,G,B channels are highly correlated to each other, SSD metric is very likely to work. Your task is to hold the G channel as the reference and move around R and B channels over it and keep track of the SSD value for the 51x51 image regions at the center of the channels. For each channel, you will find the (x,y) displacement vector that gives the minimum SSD value.
The program should divide the image into three equal parts. The first image is Blue Channel, the second one is Green channel and the last one is Red channel.
You have to name your variables as below
Blue channel Image - B
Green channel Image - G
Red channel Image - R
Reference Green Channel center region (51x51) - ref_img_region (center of this region coincides with the center of image and indexes are always integers)
Final aligned image - ColorImg_aligned
Given input image-
Required output image-
I have done this so far and getting the almost same output as required but the compiler is showing incorrect value for ColorImg_aligned.
What's wrong with my code. I am new to Matlab. Sorry if the code is not efficient.
%Read the image
img = imread('course1image.jpg');
[r,c] = size(img);
B = img(1:r/3,:);
G = img((r/3)+1:(2*r/3),:);
R = img((2*r/3)+1:r,:);
ref_img_region = G;
[rg,cg] = size(ref_img_region);
ref_img_region = ref_img_region(ceil((rg-50)/2) :ceil((rg-50)/2) + 50,ceil((cg-50)/2) :ceil((cg-50)/2) + 50);
%disp(size(ref_img_region));
ref_img_region = double(ref_img_region);
% Naive way
% ColorImg_aligned = cat(3,R,G,B);
% imshow(ColorImg_aligned);
% SSD way
nR = align(G,R);
nB = align(G,B);
ColorImg_aligned = cat(3,nR,G,nB);
imshow(ColorImg_aligned);
function aligned = align(green,red)
[red_row,red_col] = size(red);
[green_row,green_col] = size(green);
% checking SSD for cropped part of the images for faster calculation
cropped_red = red(ceil((red_row-50)/2) : ceil((red_row-50)/2) + 50,ceil((red_col-50)/2) :ceil((red_col-50)/2) + 50);
cropped_green = green(ceil((green_row-50)/2) : ceil((green_row-50)/2) + 50,ceil((green_col-50)/2) :ceil((green_col-50)/2) + 50);
MiN = 9999999999;
r_index = 0;
r_dim = 1;
for i = -10:10
for j = 1:2
ssd = SSD(cropped_green,circshift(cropped_red,i,j));
if ssd < MiN
MiN = ssd;
r_index = i;
r_dim = j;
end
end
end
aligned = circshift(red,r_index,r_dim);
end
function ssd = SSD(a1,a2)
x = double(a1)-double(a2);
ssd = sum(x(:).^2);
end
Finally I was able to pass the assignment.
I just changed Y = circshift(A,K,dim)version of circshift to Y = circshift(A,[i,j])I'm still doing the same thing but the compiler accepted the answer this time.
Anybody having thoughts about why this happened?
After modification the code looks like this.
%Read the image
img = imread('course1image.jpg');
[r,c] = size(img);
B = img(1:r/3,:);
G = img((r/3)+1:(2*r/3),:);
R = img((2*r/3)+1:r,:);
ref_img_region = G;
[rg,cg] = size(ref_img_region);
ref_img_region = ref_img_region(ceil((rg-50)/2) :ceil((rg-50)/2) + 50,ceil((cg-50)/2) :ceil((cg-50)/2) + 50);
%disp(size(ref_img_region));
ref_img_region = double(ref_img_region);
% Naive way
% ColorImg_aligned = cat(3,R,G,B);
% imshow(ColorImg_aligned);
% SSD way
nR = align(G,R);
nB = align(G,B);
ColorImg_aligned = cat(3,nR,G,nB);
imshow(ColorImg_aligned);
function aligned = align(green,red)
[red_row,red_col] = size(red);
[green_row,green_col] = size(green);
% checking SSD for cropped part of the images for faster calculation
cropped_red = red(ceil((red_row-50)/2) : ceil((red_row-50)/2) + 50,ceil((red_col-50)/2) :ceil((red_col-50)/2) + 50);
cropped_green = green(ceil((green_row-50)/2) : ceil((green_row-50)/2) + 50,ceil((green_col-50)/2) :ceil((green_col-50)/2) + 50);
MiN = 9999999999;
r_index = 0;
r_dim = 1;
% Modifications
for i = -10:10
for j = -10:10
ssd =
SSD(cropped_green,circshift(cropped_red,[i,j])); %circshift(A,[i,j])
if ssd < MiN
MiN = ssd;
r_index = i;
r_dim = j;
end
end
end
aligned = circshift(red,[r_index,r_dim]);
end
function ssd = SSD(a1,a2)
x = double(a1)-double(a2);
ssd = sum(x(:).^2);
end
Output
I = imread('Sub1.png');
figure, imshow(I);
I = imcomplement(I);
I = double(I)/255;
I = adapthisteq(I,'clipLimit',0.0003,'Distribution','exponential');
k = 12;
beta = 2;
maxIter = 100;
for i=1:length(beta)
[seg,prob,mu,sigma,it(i)] = ICM(I, k, beta(i), maxIter,5);
pr(i) = prob(end);
hold on;
end
figure, imshow(seg,[]);
and ICM function is defined as
function [segmented_image,prob,mu,sigma,iter] = ICM(image, k, beta, max_iterations, neigh)
[width, height, bands] = size(image);
image = imstack2vectors(image);
segmented_image = init(image,k,1);
clear c;
iter = 0;
seg_old = segmented_image;
while(iter < max_iterations)
[mu, sigma] = stats(image, segmented_image, k);
E1 = energy1(image,mu,sigma,k);
E2 = energy2(segmented_image, beta, width, height, k);
E = E1 + E2;
[p2,~] = min(E2,[],2);
[p1,~] = min(E1,[],2);
[p,segmented_image] = min(E,[],2);
prob(iter+1) = sum(p);
%find mismatch with previous step
[c,~] = find(seg_old~=segmented_image);
mismatch = (numel(c)/numel(segmented_image))*100;
if mismatch<0.1
iter
break;
end
iter = iter + 1;
seg_old = segmented_image;
end
segmented_image = reshape(segmented_image,[width height]);
end
Output of my algorithm is a logical matrix (seg) of size 305-by-305. When I use
imshow(seg,[]);
I am able to display the image. It shows different component with varying gray value. But bwlabel returns 1. I want to display the connected components. I think bwlabel thresholds the image to 1. unique(seg) returns values 1 to 10 since number of classes used in k-means is 10. I used
[label n] = bwlabel(seg);
RGB = label2rgb(label);
figure, imshow(RGB);
I need all the ellipse-like structures which are in between the two squares close to the middle of the image. I don't know the number of classes present in it.
Input image:
Ground truth:
My output:
If you want to explode the label image to different connected components you need to use a loop to extract labels for each class and sum label images to get the out label image.
u = unique(seg(:));
out = zeros(size(seg));
num_objs = 0;
for k = 1: numel(u)
mask = seg==u(k);
[L,N] = bwlabel(mask);
L(mask) = L(mask) + num_objs;
out = out + L;
num_objs = num_objs + N ;
end
mp = jet(num_objs);
figure,imshow(out,mp)
Something like this is produced:
I have tried to do everything out of scratch. I wish it is of some help.
I have a treatment chain that get at first contours with parameters tuned on a trial-and-error basis, I confess. The last "image" is given at the bottom ; with it, you can easily select the connected components and do for example a reconstruction by markers using "imreconstruct" operator.
clear all;close all;
I = imread('C:\Users\jean-marie.becker\Desktop\imagesJPG10\spinalchord.jpg');
figure,imshow(I);
J = I(:,:,1);% select the blue channel because jpg image
J=double(J<50);% I haven't inverted the image
figure, imshow(J);
se = strel('disk',5);
J=J-imopen(J,se);
figure, imshow(J);
J=imopen(J,ones(1,15));% privilegizes long horizontal strokes
figure, imshow(J);
K=imdilate(J,ones(20,1),'same');
% connects verticaly not-to-far horizontal "segments"
figure, imshow(K);
I have implemented Niblack thresholding onto an image in MATLAB (R2014B) as such:
function [ ] = processing_local( )
x = imread('HW8.png');
% Resize the image.
size(x);
x = imresize(x,[500 800]);
figure;
imshow(x);
title('Original');
x = imadjust(x, [0.2,0.8],[0.5,1.0]);
% HSV plane, extracting the value part.
z = rgb2hsv(x);
v = z(:,:,3);
v = imadjust(v);
% Finding the mean and standard deviation.
m = mean(v(:));
s = std(v(:));
k = -.4;
value = m+ k*s;
temp = v;
% Niblack
for p = 1:1:500
for q = 1:1:800
pixel = temp(p,q);
if(pixel > value)
temp(p,q)= 1;
else
temp(p,q)= 0;
end
end
end
figure;
imshow(temp);
title('Niblack Result.');
end
The result I see is this:
Output of Niblack thresholding
As shown there is a lot of dark spots where the image has been degraded, how would I optimize this in MATLAB?
I would like to try to some uniform brightness but cannot implement this within the function. I have wrote it in a separate function like this:
function [ ] = practice_white( )
x = imread('HW4.png');
x = rgb2gray(x);
background = imopen(x,strel('disk',15));
white = imclose(x, background);
whiteAdjusted = x ./ (white)*0.85;
BW = imbinarize(whiteAdjusted, 0.2);
figure
imshow(BW); title('Test');
end
Normally, a Gabor filter, as its name suggests, is used to filter an image and extract everything that it is oriented in the same direction of the filtering.
In this question, you can see more efficient code than written in this Link
Assume 16 scales of Filters at 4 orientations, so we get 64 gabor filters.
scales=[7:2:37], 7x7 to 37x37 in steps of two pixels, so we have 7x7, 9x9, 11x11, 13x13, 15x15, 17x17, 19x19, 21x21, 23x23, 25x25, 27x27, 29x29, 31x31, 33x33, 35x35 and 37x37.
directions=[0, pi/4, pi/2, 3pi/4].
The equation of Gabor filter in the spatial domain is:
The equation of Gabor filter in the frequency domain is:
In the spatial domain:
function [fSiz,filters,c1OL,numSimpleFilters] = init_gabor(rot, RF_siz)
image=imread('xxx.jpg');
image_gray=rgb2gray(image);
image_gray=imresize(image_gray, [100 100]);
image_double=double(image_gray);
rot = [0 45 90 135]; % we have four orientations
RF_siz = [7:2:37]; %we get 16 scales (7x7 to 37x37 in steps of two pixels)
minFS = 7; % the minimum receptive field
maxFS = 37; % the maximum receptive field
sigma = 0.0036*RF_siz.^2 + 0.35*RF_siz + 0.18; %define the equation of effective width
lambda = sigma/0.8; % it the equation of wavelength (lambda)
G = 0.3; % spatial aspect ratio: 0.23 < gamma < 0.92
numFilterSizes = length(RF_siz); % we get 16
numSimpleFilters = length(rot); % we get 4
numFilters = numFilterSizes*numSimpleFilters; % we get 16x4 = 64 filters
fSiz = zeros(numFilters,1); % It is a vector of size numFilters where each cell contains the size of the filter (7,7,7,7,9,9,9,9,11,11,11,11,......,37,37,37,37)
filters = zeros(max(RF_siz)^2,numFilters); % Matrix of Gabor filters of size %max_fSiz x num_filters, where max_fSiz is the length of the largest filter and num_filters the total number of filters. Column j of filters matrix contains a n_jxn_j filter (reshaped as a column vector and padded with zeros).
for k = 1:numFilterSizes
for r = 1:numSimpleFilters
theta = rot(r)*pi/180; % so we get 0, pi/4, pi/2, 3pi/4
filtSize = RF_siz(k);
center = ceil(filtSize/2);
filtSizeL = center-1;
filtSizeR = filtSize-filtSizeL-1;
sigmaq = sigma(k)^2;
for i = -filtSizeL:filtSizeR
for j = -filtSizeL:filtSizeR
if ( sqrt(i^2+j^2)>filtSize/2 )
E = 0;
else
x = i*cos(theta) - j*sin(theta);
y = i*sin(theta) + j*cos(theta);
E = exp(-(x^2+G^2*y^2)/(2*sigmaq))*cos(2*pi*x/lambda(k));
end
f(j+center,i+center) = E;
end
end
f = f - mean(mean(f));
f = f ./ sqrt(sum(sum(f.^2)));
p = numSimpleFilters*(k-1) + r;
filters(1:filtSize^2,p)=reshape(f,filtSize^2,1);
fSiz(p)=filtSize;
end
end
% Rebuild all filters (of all sizes)
nFilts = length(fSiz);
for i = 1:nFilts
sqfilter{i} = reshape(filters(1:(fSiz(i)^2),i),fSiz(i),fSiz(i));
%if you will use conv2 to convolve an image with this gabor, so you should also add the equation below. But if you will use imfilter instead of conv2, so do not add the equation below.
sqfilter{i} = sqfilter{i}(end:-1:1,end:-1:1); %flip in order to use conv2 instead of imfilter (%bug_fix 6/28/2007);
convv=imfilter(image_double, sqfilter{i}, 'same', 'conv');
figure;
imagesc(convv);
colormap(gray);
end
phi = ij*pi/4; % ij = 0, 1, 2, 3
theta = 3;
sigma = 0.65*theta;
filterSize = 7; % 7:2:37
G = zeros(filterSize);
for i=(0:filterSize-1)/filterSize
for j=(0:filterSize-1)/filterSize
xprime= j*cos(phi);
yprime= i*sin(phi);
K = exp(2*pi*theta*sqrt(-1)*(xprime+ yprime));
G(round((i+1)*filterSize),round((j+1)*filterSize)) =...
exp(-(i^2+j^2)/(sigma^2))*K;
end
end
As of R2015b release of the Image Processing Toolbox, you can create a Gabor filter bank using the gabor function in the image processing toolbox, and you can apply it to an image using imgaborfilt.
In the frequency domain:
sigma_u=1/2*pi*sigmaq;
sigma_v=1/2*pi*sigmaq;
u0=2*pi*cos(theta)*lambda(k);
v0=2*pi*sin(theta)*lambda(k);
for u = -filtSizeL:filtSizeR
for v = -filtSizeL:filtSizeR
if ( sqrt(u^2+v^2)>filtSize/2 )
E = 0;
else
v_theta = u*cos(theta) - v*sin(theta);
u_theta = u*sin(theta) + v*cos(theta);
E=(1/2*pi*sigma_u*sigma_v)*((exp((-1/2)*(((u_theta-u0)^2/sigma_u^2))+((v_theta-v0)^2/sigma_v^2))) + (exp((-1/2)*(((u_theta+u0)^2/sigma_u^2))+((v_theta+v0)^2/sigma_v^2))));
end
f(v+center,u+center) = E;
end
end