VLFeat's Image Mosaicing in Matlab - sift

The following is a piece of code that forms a Mosaic of two images after computing the Homography Matrix H using RANSAC pror to which SIFT was used to compute the descriptors:
% --------------------------------------------------------------------
% Mosaic
% --------------------------------------------------------------------
box2 = [1 size(im2,2) size(im2,2) 1 ;
1 1 size(im2,1) size(im2,1) ;
1 1 1 1 ] ;
box2_ = inv(H) * box2 ;
box2_(1,:) = box2_(1,:) ./ box2_(3,:) ;
box2_(2,:) = box2_(2,:) ./ box2_(3,:) ;
ur = min([1 box2_(1,:)]):max([size(im1,2) box2_(1,:)]) ;
vr = min([1 box2_(2,:)]):max([siize(im1,1) box2_(2,:)]) ;
[u,v] = meshgrid(ur,vr) ;
im1_ = vl_imwbackward(im2double(im1),u,v) ;
z_ = H(3,1) * u + H(3,2) * v + H(3,3) ;
u_ = (H(1,1) * u + H(1,2) * v + H(1,3)) ./ z_ ;
v_ = (H(2,1) * u + H(2,2) * v + H(2,3)) ./ z_ ;
im2_ = vl_imwbackward(im2double(im2),u_,v_) ;
mass = ~isnan(im1_) + ~isnan(im2_) ;
im1_(isnan(im1_)) = 0 ;
im2_(isnan(im2_)) = 0 ;
mosaic = (im1_ + im2_) ./ mass ;
figure(2) ; clf ;
imagesc(mosaic) ; axis image off ;
title('Mosaic') ;
if nargout == 0, clear mosaic ; end
end
Now I understand we need to warp the images in someway before stitching them using the computed Homography?
What then, is the logic behind the definition of "box2" i.e why consider the size of the first and second dimension of im2? Also, what is the function of mass and the lines of code that follow?

The content of box2 is simply the bounding box (corner coordinates) of the second image; box2_ is then this bounding box transformed into the coordinate system of im1 - in which you compute the range of coordinates (ur and vr) where to project im2 after transformation.
The purpose of variable mass is just to indicate how many images cover each pixel: If only one image is nonempty at a given pixel, its mass(...)=1 and the result equals to the value from this image. If both images are nonempty, mass(...)=2 results in computing their mean value.

Related

What data-type is used for images?

I was deriving NDVI (Normalized Difference Vegetation Index), which is a ratio of (NIR-R)/(NIR+R) where NIR is Near-Infrared band and R is Red band. This index ranges from -1 to 1. So I wrote a pyopencl code and here is what I have done and observed.
Python code:
import pyopencl as cl
import cv2
from PIL import Image
import numpy as np
from time import time
import matplotlib.pyplot as plt
#get kernel file
def getKernel():
kernel = open('kernel.c').read()
return kernel
#return images as numpy int32 arrays
def convToArray(im_r,im_nir):
a = np.asarray(im_r).astype(np.int32)
b = np.asarray(im_nir).astype(np.int32)
return a,b
#processing part
def getDerivation(platform,device,im_r,im_nir):
#setting device
pltfrm = cl.get_platforms()[platform]
dev = pltfrm.get_devices()[device]
cntx = cl.Context([dev])
queue = cl.CommandQueue(cntx)
#get 2Darrays
r,nir = convToArray(im_r,im_nir)
#shape of array
x = r.shape[1]
mf = cl.mem_flags
bs = time()
#input images buffer
inR = cl.Buffer(cntx,mf.READ_ONLY | mf.COPY_HOST_PTR,hostbuf=r)
inIR = cl.Buffer(cntx,mf.READ_ONLY | mf.COPY_HOST_PTR,hostbuf=nir)
#output image buffers
ndvi = cl.Buffer(cntx,mf.WRITE_ONLY,r.nbytes)
be = time()
print("Buffering time: " + str(be-bs) + " sec")
ts = time()
#load kernel
task = cl.Program(cntx,getKernel()%(x)).build()
#execute the process
task.derive(queue,r.shape,None,inR,inIR,ndvi)
#create empty buffer to store result
Vout = np.empty_like(r)
#dump output buffers to empty arrays
cl.enqueue_copy(queue,Vout,ndvi)
te = time()
#convert arrays to gray - image compatible formate
NDVI = Vout.astype(np.uint8)
print("Processing time: " + str(te - ts) + " On: " + pltfrm.name + " --> " + dev.name)
return NDVI
def process(platform,device,im_r,im_nir):
NDVI,NDBI,NDWI = getDerivation(platform,device,im_g,im_r,im_nir,im_swir)
print(NDVI)
cv2.imshow("NDVI",NDVI)
cv2.waitKey(0)
if __name__ == '__main__':
R = cv2.imread("BAND3.jpg",0)
NIR = cv2.imread("BAND4.jpg",0)
print(R.dtype) #returns uint8
process(0,0,R,NIR) #(0,0) is my intel gpu
kernel code(C):
__kernel void derive(__global int* inR,__global int* inIR,__global int* ndvi){
int x = get_global_id(0);
int y = get_global_id(1);
int width = %d;
int index = x + y*width;
//ndvi ratio (-1 to 1)
int a = ((inIR[index] - inR[index])/(inIR[index] + inR[index])) * (256);
a = (a < (0) ? (-1*a) : (a));
a = (a > (255) ? (255) : (a));
ndvi[index] = (a);
}
input image R:
input image NIR:
both the images have bit depth of 8
BUT I GET JUST A BLANK IMAGE. I wrote the result on the command line for debugging reasons initially,
command line output:
(1151, 1151)
Buffering time: 0.015959739685058594 sec
Processing time: 0.22115755081176758 On: Intel(R) OpenCL --> Intel(R) HD Graphics 520
[[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
Now what i think is i may not be using proper datatype for the images? also, in the kernel the line ((inIR[index] - inR[index])/(inIR[index] + inR[index])) will gives a float value, which i multiply with 256 to get a pixel value for that respective float value. So is it there the problem? Does any one know where i am going wrong?
Help is much appreciated!
Okay ... i got it. I just changed the datatype in the line a = np.asarray(im_r).astype(np.int32) in the function convToArray() to float32 and in the kernel file, i changed the parameter type to float and added int a = (int)((((float)(inIR[index] - inR[index])/(float)(inIR[index] + inR[index]))+1)*127.5); for the calculation. However, i need an explaination, why this worked and not the other way... I probably can think like, the result what we get after this calculation, int type loses data while conversion from float...is it?

How can i concatenate three 2D arrays which contain hue, saturation and intensity values in their respective arrays and display that as an image?

I am new to image processing and python. As you can see from my code, i managed to convert my RGB image to HSI by using the different formulas that i found.
I stored the values of hue, saturation and intensity in three different arrays. That is also in the code down below. How can i concatenate those three arrays and display the concatenated image as an image?
import math
from PIL import Image
img = Image.open("D:\\Texture analysis\\trees-clolorful-aerial-view-wallpaper.jpg")
rgb_img = img.convert('RGB')
row, col = img.size
print(row, col)
i = j = 0
satValue = 0
inValue = 0
hueValue = 0
squareValue = 0
hueArray = [[0 for x in range(row)] for y in range(col)]
satArray = [[0 for x in range(row)] for y in range(col)]
inArray = [[0 for x in range(row)] for y in range(col)]
division = 0
denominator = 0
numerator = 0
radAngle = 0
degAngle = 0
product = 0
sqr = 0
count = 0
uCount = 0
while i < row:
j = 0
while j < col:
red, green, blue = rgb_img.getpixel((i, j))
hRed = sRed = iRed = red
hGreen = sGreen = iGreen = green
hBlue = sBlue = iBlue = blue
# =========================Saturation Calculation==============================
if sRed == 0 and sGreen == 0 and sBlue == 0:
satValue = 0
satArray[i][j] = 0
else:
if (sRed < sGreen) and (sRed < sBlue):
satValue = 1 - (((3) * (sRed)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
elif (sGreen < sRed) and (sGreen < sBlue):
satValue = 1 - (((3) * (sGreen)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
else:
satValue = 1 - (((3) * (sBlue)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
# =============================================================================
# ==========================Intensity Calculation==============================
inValue = (iRed + iGreen + iBlue) / 3
inArray[i][j] = inValue
count += 1
print(inValue, count)
# =============================================================================
# =============================Hue Calculation=================================
product = (hRed - hBlue) * (hGreen - hBlue)
sqr = (hRed - hGreen) * (hRed - hGreen)
denominator = math.sqrt(sqr + product)
if denominator != 0:
numerator = ((hRed - hGreen) + (hRed - hBlue)) / 2
division = numerator / denominator
radAngle = math.acos(division)
degAngle = math.degrees(radAngle)
if hBlue <= hGreen:
hueValue = degAngle
hueArray[i][j] = hueValue
elif hBlue > hGreen:
hueValue = 360 - degAngle
hueArray[i][j] = hueValue
elif denominator == 0:
hueValue = 0
hueArray[i][j] = hueValue
#print(hueValue, count)
# =============================================================================
j += 1
i += 1 print(i, j)
PS. You will be seeing a lot of my amateur code in the future as well :D
I can see what's going wrong now I am back at a computer. You probably tried this:
#!/usr/bin/env python3
from PIL import Image
img = Image.open('start.png')
hsvimg = img.convert('HSV')
hsvimg.save('result.png')
And if you do that, you actually get an error message:
OSError: cannot write mode HSV as PNG
because, PNG images are always in sRGB colourspace, so it correctly declines to write your HSV image. The thing is though, that the colourspace conversion actually worked and the values in the image actually are the HSV values that you want. You can check this with:
img.getpixel((X,Y))
and
hsvimg.getpixel((X,Y))
where X and Y are any random coordinates you like. You will see the the latter is always the correct HSV representation of the former's RGB colour.
I am not sure what you are trying to do overall, so I can't really advise properly, but one thing you could do is "lie through your teeth" and tell PIL/Pillow that the image is RGB even though you know it is HSV. So if you do:
hsvimg = img.convert('HSV')
hsvimg.mode='RGB' # Tell PIL image is RGB
hsvimg.save('result.png')
it will save an image but it, and all other viewers, will show your Hue as Blue, your Saturation as Green and your Value as Blue.
I am guessing you have other processing to do, and this is only an intermediate aspect of your processing, so it probably won't matter and you can probably carry on and do your processing and convert back at the end and save to an sRGB PNG file without needing to lie.
In answer to your actual question, you can split and merge channels like this with PIL/Pillow:
# Split and recombine with PIL
r,g,b = img.split()
merged = Image.merge(mode='RGB',bands=(r,g,b)))
Or, if you prefer Numpy which is often faster:
# Open image as Numpy array
img = np.array(Image.open('start.png'))
# Split into 3 channels/arrays/bands
r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]
# Recombine to single image
merged = np.dstack((r, g, b))

TypeError: 'numpy.ndarray' object is not callable

I have seen other people asking something similar but I can not figure out the problem anyway.
I am trying to translate a Matlab code to Python and I have a problem after the following line in the FOR loop:
dx = abs(np.diff(g_coord(num)))
Below you have the code up to that loop. Any help will be appreciated. I really tried to fix it by myself but unsuccessfully. Sorry if it is a stupid mistake. The MATLAB lines are kept as Python comments in case it helps.
import numpy as np
from scipy.sparse import lil_matrix
# physical parameters
seconds_per_yr = 60*60*24*365; # number of seconds in one year
lx = 10000 ; #length of spatial domain (m)
Cp = 1e3 ; # rock heat capacity (J/kg/K)
rho = 2700 ; # rock density (kg/mˆ3)
K = 3.3 ; # bulk thermal conductivity (W/m/K)
kappa = K/(Cp*rho); # thermal diffusivity (mˆ2/s)
Tb = 0 ; # temperatures at boundaries (o C)
A = 2.6e-6 ; # heat production (W/mˆ3)
H = A/(rho*Cp); # heat source term (o K/s) % numerical parameters
dt = 1000*seconds_per_yr ; # time step (s)
ntime = 5000 ; # number of time steps
nels = 40 ; # total number of elements
nod = 2 ; # number of nodes per element
nn = nels+1 # total number of nodes
dx = lx/nels ; # element size
g_coord = np.arange(0, lx+1, dx)#[0:dx:lx]
bcdof = np.array([1, nn]); #[ 1 nn ] ; boundary nodes
bcval = np.array([Tb, Tb]); #[ Tb Tb ] ; # boudary values
g_num = np.zeros((nod, nels), float); #zeros(nod,nels) ;
g_num[0,:]=np.arange(1, nn); #g_num(1,:) = [1:nn-1] ;
g_num[1,:]=np.arange(2, nn+1); #g_num(2,:) = [2:nn] ;
# initialise matrices and vectors
ff = np.zeros((nn,1), float); # system load vector
b = np.zeros((nn,1), float); # system rhs vector
lhs=lil_matrix((nn, nn)) #lhs = sparse(nn,nn); system lhs matrix
rhs=lil_matrix((nn, nn)) #rhs = sparse(nn,nn); system rhs matrix
displ = np.zeros((nn,1), float); # initial temperature (o C)
#-----------------------------------------------------
# matrix assembly
#-----------------------------------------------------
# Matlab version of the loop
#-----------------------------------------------------
#for iel=1:nels # loop over all elements
# num = g_num(:,iel) ; # retrieve equation number
# dx = abs(diff(g_coord(num))) ; # length of element
# MM = dx*[1/3 1/6 ; 1/6 1/3 ] ;# mass matrix
# KM = [kappa/dx -kappa/dx ; -kappa/dx kappa/dx ]; #diffn matrix
# F = dx*H*[1/2 ; 1/2] ; # load vector
# lhs(num,num) = lhs(num,num) + MM/dt + KM ; # assemble lhs
# rhs(num,num) = rhs(num,num) + MM/dt ; # assemble rhs
# ff(num) = ff(num) + F ; # assemble load
#end # end of element loop
#Python version of the loop
#-----------------------------------------------------
for iel in range(0, nels): # loop over all elements
num = g_num[:,iel] # retrieve equation number
#print(num)
dx = abs(np.diff(g_coord[num])) # length of element
MM = dx*(np.array([[1/3, 1/6],[1/6, 1/3]])) # mass matrix
KM = np.array([[kappa/dx, -kappa/dx],[-kappa/dx, kappa/dx]])
F = dx*H*(np.array([1/2, 1/2])).reshape(-1,1) # load vector
lhs[num,num] = lhs[num,num] + MM/dt + KM # assemble lhs
rhs[num,num] = rhs[num,num] + MM/dt # assemble rhs
ff[num] = ff[num] + F # assemble load
The error seems to be because num is a float.
Simply do:
dx = abs(np.diff(g_coord[np.int32(num)]))
However it raises another error a few lines later because num is a 2-element array. You know what the code should do which I do not. If you have more issues, you can comment below or edit your question with the first problem solved.
Also, I noticed that you left all the ; at the end of the lines as in Matlab. You do not need this in Python. Also, I think there is no need for you to specify float when you create the matrices of zeros, they naturally are float.

Polyline() - change colour with an array value

I'm trying to create a very simple example of a for steps in [] loop using a Polyline() inside an IronPython WPF application. Each iteration of the loop should draw a different colour however Brushes implements a set of predefined System.Windows.Media.SolidColorBrush objects. I can't work out how to swap Red for my steps variable.
def polylineShape(self):
x = self.myCanvas.Width/2
y = self.myCanvas.Height/2
polyline = Polyline()
polyline.StrokeThickness = 5
for steps in ['Red','Blue','Green','Black']:
x = x
y = x
polyline.Points.Add(Point(x,y))
x = x + 40
polyline.Points.Add(Point(x,y))
polyline.Stroke = Brushes.Red #change colour on iteration
self.myCanvas.Children.Add(polyline)
I created a solution with some trial and error, I couldn't work out how to pass colours directly to the Brushes type.
def polylineShape(self):
x = 0
y = 0
for steps in [Brushes.SteelBlue, Brushes.DarkOrange, Brushes.DarkSeaGreen, Brushes.Honeydew]:
polyline = Polyline()
polyline.StrokeThickness = self.myCanvas.Height/4
x = 0
y = y + self.myCanvas.Height/4
polyline.Points.Add(Point(x,y))
x = self.myCanvas.Width
polyline.Points.Add(Point(x,y))
polyline.Stroke = steps
self.myCanvas.Children.Add(polyline)

MATLAB: search for elements in an array matching multidimensional condition

I have a column vector (V1) of real numbers like:
123.2100
125.1290
...
954.2190
If I add, let's say, a number 1 to each row in this vector, I will get (V2):
124.2100
126.1290
...
955.2190
I need to find out how many elements from V2 are inside some error-window created from V1. For example the error-window = 0.1 (but in my case every element in V1 has it's own error window):
123.1100 123.3100
125.0290 125.2290
...
954.1190 954.3190
I can create some code like this:
% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x
% (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
% corresponding to different mdiff temp = 0;
for i = 1:length(mdiff)
for j = 1:size(window,1)
xx = x + mdiff(i);
indxx = find( xx => window(j,1) & xx <= window(j,2) );
if any(indxx)
temp = temp + length(indxx); %edited
end
end
cdiff(i) = temp;
temp = 0;
end
So, at the end cdiff will contain all the counts corresponding to mdiff. The only thing, I would like to make the code faster. Or is there a way to avoid using the second loop (with j)? I mean to directly use a multidimensional condition.
EDIT
I decided to simpify the code like this (thanking to the feedback I got here):
% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x
% (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
% corresponding to different mdiff temp = 0;
for i = 1:length(mdiff)
xx = x + mdiff(i);
cdiff(i) = sum(sum(bsxfun(#and,bsxfun(#ge,xx,window(:,1)'),bsxfun(#le,xx,window(:,2)'))));
end
In this case the code works faster and seems properly
add = 1; %// how much to add
error = .1; %// maximum allowed error
V2 = V1 + add; %// build V2
ind = sum(abs(bsxfun(#minus, V1(:).', V2(:)))<error)>1; %'// index of elements
%// of V1 satisfying the maximum error condition. ">1" is used to because each
%// element is at least equal to itself
count = nnz(ind);
Think this might work for you -
%%// Input data
V1 = 52+rand(4,1)
V2 = V1+1;
t= 0.1;
low_bd = any(abs(bsxfun(#minus,V2,[V1-t]'))<t,2); %%//'
up_bd = any(abs(bsxfun(#minus,V2,[V1+t]'))<t,2); %%//'
count = nnz( low_bd | up_bd )
One could also write it as -
diff_map = abs(bsxfun(#minus,[V1-t V1+t],permute(V2,[3 2 1])));
count = nnz(any(any(diff_map<t,2),1))
Edit 1:
low_bd = any(abs(bsxfun(#minus,V2,window(:,1)'))<t,2); %%//'
up_bd = any(abs(bsxfun(#minus,V2,window(:,2)'))<t,2); %%//'
count = nnz( low_bd | up_bd )
Edit 2: Vectorized form for the edited code
t1 = bsxfun(#plus,x,mdiff);
d1 = bsxfun(#ge,t1,permute(window(:,1),[3 2 1]));
d2 = bsxfun(#le,t1,permute(window(:,2),[3 2 1]));
t2 = d1.*d2;
cdiff_vect = max(sum(t2,3),[],1)';

Resources