我需要使用numpy和scipy将以下Matlab脚本转换为Python。
此脚本计算称为LPQ(局部相位定量器)的功能,该功能通常用于人脸识别。
记录LPQ特征提取的文件可以在这里找到: http://www.ee.oulu.fi/mvg/files/pdf/ICISP08.pdf 2
脚本的 Matlab 版本如下:
function LPQdesc = lpq(img,winSize,mode)
%% Defaul parameters
% Local window size
if nargin<2 || isempty(winSize)
winSize=3; % default window size 3
end
rho=0.90; % Use correlation coefficient rho=0.9 as default
% Local frequency estimation (Frequency points used [alpha,0], [0,alpha], [alpha,alpha], and [alpha,-alpha])
if nargin<4 || isempty(freqestim)
freqestim=1; %use Short-Term Fourier Transform (STFT) with uniform window by default
end
STFTalpha=1/winSize; % alpha in STFT approaches (for Gaussian derivative alpha=1)
sigmaS=(winSize-1)/4; % Sigma for STFT Gaussian window (applied if freqestim==2)
sigmaA=8/(winSize-1); % Sigma for Gaussian derivative quadrature filters (applied if freqestim==3)
% Output mode
if nargin<5 || isempty(mode)
mode='nh'; % return normalized histogram as default
end
% Other
convmode='valid'; % Compute descriptor responses only on part that have full neigborhood. Use 'same' if all pixels are included (extrapolates image with zeros).
%% Check inputs
if size(img,3)~=1
error('Only gray scale image can be used as input');
end
if winSize<3 || rem(winSize,2)~=1
error('Window size winSize must be odd number and greater than equal to 3');
end
if sum(strcmp(mode,{'nh','h','im'}))==0
error('mode must be nh, h, or im. See help for details.');
end
%% Initialize
img=double(img); % Convert image to double
r=(winSize-1)/2; % Get radius from window size
x=-r:r; % Form spatial coordinates in window
u=1:r; % Form coordinates of positive half of the Frequency domain (Needed for Gaussian derivative)
%% Form 1-D filters
% STFT uniform window
% Basic STFT filters
w0=(x*0+1);
w1=exp(complex(0,-2*pi*x*STFTalpha));
w2=conj(w1);
%% Run filters to compute the frequency response in the four points. Store real and imaginary parts separately
% Run first filter
filterResp=conv2(conv2(img,w0.',convmode),w1,convmode);
% Initilize frequency domain matrix for four frequency coordinates (real and imaginary parts for each frequency).
freqResp=zeros(size(filterResp,1),size(filterResp,2),8);
% Store filter outputs
freqResp(:,:,1)=real(filterResp);
freqResp(:,:,2)=imag(filterResp);
% Repeat the procedure for other frequencies
filterResp=conv2(conv2(img,w1.',convmode),w0,convmode);
freqResp(:,:,3)=real(filterResp);
freqResp(:,:,4)=imag(filterResp);
filterResp=conv2(conv2(img,w1.',convmode),w1,convmode);
freqResp(:,:,5)=real(filterResp);
freqResp(:,:,6)=imag(filterResp);
filterResp=conv2(conv2(img,w1.',convmode),w2,convmode);
freqResp(:,:,7)=real(filterResp);
freqResp(:,:,8)=imag(filterResp);
% Read the size of frequency matrix
[freqRow,freqCol,freqNum]=size(freqResp);
%% Perform quantization and compute LPQ codewords
LPQdesc=zeros(freqRow,freqCol); % Initialize LPQ code word image (size depends whether valid or same area is used)
for i=1:freqNum
LPQdesc=LPQdesc+(double(freqResp(:,:,i))>0)*(2^(i-1));
end
%% Switch format to uint8 if LPQ code image is required as output
if strcmp(mode,'im')
LPQdesc=uint8(LPQdesc);
end
%% Histogram if needed
if strcmp(mode,'nh') || strcmp(mode,'h')
LPQdesc=hist(LPQdesc(:),0:255);
end
%% Normalize histogram if needed
if strcmp(mode,'nh')
LPQdesc=LPQdesc/sum(LPQdesc);
end
尝试在python中转换Matlab LPQ函数我生成了以下代码:
# -*- coding: cp1253 -*-
import numpy as np
from scipy.signal import convolve2d
def lpq(img,winSize=3,decorr=0,freqestim=1,mode='nh'):
rho=0.90;
STFTalpha=1/winSize; # alpha in STFT approaches (for Gaussian derivative alpha=1)
sigmaS=(winSize-1)/4; # Sigma for STFT Gaussian window (applied if freqestim==2)
sigmaA=8/(winSize-1); # Sigma for Gaussian derivative quadrature filters (applied if freqestim==3)
convmode='valid'; # Compute descriptor responses only on part that have full neigborhood. Use 'same' if all pixels are included (extrapolates np.image with zeros).
img=np.float64(img); # Convert np.image to double
r=(winSize-1)/2; # Get radius from window size
x=np.arange(-r,r) # Form spatial coordinates in window
u=np.arange(1,r) # Form coordinates of positive half of the Frequency domain (Needed for Gaussian derivative)
if freqestim==1: # STFT uniform window
# Basic STFT filters
w0=(x*0+1);
w1=np.exp(-2*np.pi*x*STFTalpha)
w2=np.conj(w1);
## Run filters to compute the frequency response in the four points. Store np.real and np.imaginary parts separately
# Run first filter
filterResp=convolve2d(convolve2d(img,w0,convmode),w1,convmode);
# Initilize frequency domain matrix for four frequency coordinates (np.real and np.imaginary parts for each frequency).
shape0, shape1 = filterResp.shape
freqResp=np.zeros((shape0,shape1,8));
# Store filter outputs
freqResp[:,:,0]=np.real(filterResp);
freqResp[:,:,1]=np.imag(filterResp);
# Repeat the procedure for other frequencies
filterResp=convolve2d(convolve2d(img,w1.transpose(),convmode),w0,convmode);
freqResp[:,:,2]=np.real(filterResp);
freqResp[:,:,3]=np.imag(filterResp);
filterResp=convolve2d(convolve2d(img,w1.transpose(),convmode),w1,convmode);
freqResp[:,:,4]=np.real(filterResp);
freqResp[:,:,5]=np.imag(filterResp);
filterResp=convolve2d(convolve2d(img,w1.transpose(),convmode),w2,convmode);
freqResp[:,:,6]=np.real(filterResp);
freqResp[:,:,7]=np.imag(filterResp);
# Read the size of frequency matrix
freqRow,freqCol,freqNum=freqResp.shape;
## Perform quantization and compute LPQ codewords
LPQdesc=np.zeros((freqRow,freqCol)); # Initialize LPQ code word np.image (size depends whether valid or same area is used)
for i in range(0, freqNum):
LPQdesc=LPQdesc+((freqResp[:,:,i])>0)*(2^(i-1));
## Switch format to uint8 if LPQ code np.image is required as output
if mode=='im':
LPQdesc=uint8(LPQdesc);
## Histogram if needed
if mode=='nh' or mode=='h':
LPQdesc=np.histogram(LPQdesc[:],range(256));
## Normalize histogram if needed
if mode=='nh':
LPQdesc[0]=LPQdesc[0]/sum(LPQdesc[0]);
print LPQdesc[0]
return LPQdesc[0]
然而,在执行同一图像的python脚本后,我收到以下错误:
Traceback (most recent call last):
File "C:\Users\user\Desktop\source\lpq_parametric.py", line 58, in lpq
filterResp=convolve2d(convolve2d(img,w0,convmode),w1,convmode);
File "C:\Python27\lib\site-packages\scipy\signal\signaltools.py", line 548, in convolve2d
out = sigtools._convolve2d(in1, in2, 1, val, bval, fillvalue)
ValueError: object of too small depth for desired array
由于我是python中的菜鸟和scipy / numpy,我需要帮助将这个python脚本置于功能状态。你能帮我修一下脚本中的错误吗?
答案 0 :(得分:13)
问题似乎与w0,w1和w2有关。 Matlab没有1D数组,所以如果你创建了一个1D数组,它会自动转换为2D数组。然而,numpy确实有1D数组,而arange会生成1D数组。
在这种情况下,从x派生的x和w0,w1和w2都是1D数组。顾名思义,convolve2d需要2D数组。另一方面,img可能是2D阵列。这就是你收到错误的原因。
解决方案是将您的1D x转换为2D值。然后,这将通过涉及x的其他操作继续进行,使w0,w1和w2也成为2D。
这两种方法都应该有效:
x=np.atleast_2d(np.arange(-r,r))
或
x=np.arange(-r,r)[np.newaxis]
第一种情况总是使数组为2D或更高,而第二种情况则添加一个新维度,无论当前维度是什么。既然您已经了解了维度,那就不是问题了。
虽然由于错误而无法访问它,但您的转置操作也无法按预期工作,因为1D数组的转置不会执行任何操作。这也将解决这个问题。
另外,还有其他三件事:
首先,您不需要在行尾添加分号(;)。当它放在Python的一行末尾时它什么都不做。
其次,你正在努力转移。简单的方法是:
filterResp=convolve2d(convolve2d(img,w1.T,convmode),w0,convmode)
第三,可能更容易做类似的事情:
filterResp1=convolve2d(convolve2d(img,w1.T,convmode),w0,convmode)
filterResp2=convolve2d(convolve2d(img,w1.T,convmode),w1,convmode)
filterResp3=convolve2d(convolve2d(img,w1.T,convmode),w2,convmode)
freqResp=np.dstack([np.real(filterResp1),
np.imag(filterResp1),
np.real(filterResp2),
np.imag(filterResp2),
np.real(filterResp3),
np.imag(filterResp3),
np.real(filterResp4),
np.imag(filterResp4)])
<强>更新强>
我注意到还有许多其他问题在阅读代码:
首先,如果您使用的是python 2.x,那么默认情况下,整数除法会返回一个整数。所以,例如,1/2 == 0。要更改这个1/2 ==。5,然后将其添加到现有导入之上:
from __future__ import division
这在python 3.x中不是问题。
接下来,在python中,np.arange不包括上端,所以:
x=np.arange(-r,r)
应该是:
x=np.arange(-r,r+1)[np.newaxis]
接下来,该行的Matlab版本使用复数:
w1=exp(complex(0,-2*pi*x*STFTalpha));
python版本没有。这意味着python和Matlab版本之间的w1和w2都不同。所以:
w1=np.exp(-2*np.pi*x*STFTalpha)
应该是:
w1=np.exp(-2*np.pi*x*STFTalpha*1j)
接下来,在matlab版本中,您将转置第一个w0:
filterResp=conv2(conv2(img,w0.',convmode),w1,convmode);
在python版本中你不是,所以:
filterResp=convolve2d(convolve2d(img,w0,convmode),w1,convmode);
应该是:
filterResp=convolve2d(convolve2d(img,w0.T,convmode),w1,convmode)
接下来,在python版本中,我已经从0开始,所以从中减去1会改变与Matlab版本相比的值。另外,python使用**代表幂,而不是^(在python中是^二进制异或)。所以:
for i in range(0, freqNum):
LPQdesc=LPQdesc+((freqResp[:,:,i])>0)*(2^(i-1))
应该是:
for i in range(0, freqNum):
LPQdesc=LPQdesc+((freqResp[:,:,i])>0)*(2**i)
接下来,在Matlab中,如你所知,arr(:)会使数组变平。在python中不是这种情况。 Python使用arr.flatten()。并且直方图返回您不想要的bin边缘。所以你需要改变:
LPQdesc=np.histogram(LPQdesc[:],range(256));
为:
LPQdesc=np.histogram(LPQdesc.flatten(),range(256))[0]
一旦你这样做,为了保持与Matlab版本相同的东西,你需要改变:
if mode=='nh':
LPQdesc[0]=LPQdesc[0]/sum(LPQdesc[0]);
print LPQdesc[0]
return LPQdesc[0]
到:
if mode=='nh':
LPQdesc=LPQdesc/sum(LPQdesc)
print LPQdesc
return LPQdesc
接下来,虽然这不是错误,但您可以简化:
w0=(x*0+1);
要:
w0=np.ones_like(x);
最后,我不知道这条线可能如何运作:
LPQdesc=uint8(LPQdesc);
您可能没有尝试过模式==&#39; im&#39;。该行应该是:
LPQdesc=np.uint8(LPQdesc)
也不是错误,但你可以使用arr.real和arr.imag来获取python中的实部和虚部,并使用arr.sum()来获得总和。
也不是错误,但是因为在python中使用子数组并不占用任何额外的内存,所以:
# Read the size of frequency matrix
freqRow,freqCol,freqNum=freqResp.shape
## Perform quantization and compute LPQ codewords
LPQdesc=np.zeros((freqRow,freqCol))
可以成为:
LPQdesc=np.zeros_like(freqResp[:,:,0])
接下来,你永远不会使用你,所以你可以完全摆脱这条线(如果你有你,你会再次需要r + 1):
u=np.arange(1,r)
你也从未使用过装饰。
接下来,如果freqestim不是1,你永远不会计算w0,w1或w2,所以如果你试图运行除1之外的任何freqstim值,你的程序将会崩溃。我无法解决这个问题,因为我没有&# 39;不知道如何处理freqstim的其他值。
最后,在Matlab和Python中,使用循环表示总和很慢。 Python允许您将低维数组广播到更高维度,因此您可以执行以下操作:
inds = np.arange(freqResp.shape[2])[np.newaxis,np.newaxis,:]
LPQdesc=((freqResp>0)*(2**inds)).sum(2)
所以你的最终python函数看起来应该是这样的:
# -*- coding: cp1253 -*-
from __future__ import division
import numpy as np
from scipy.signal import convolve2d
def lpq(img,winSize=3,freqestim=1,mode='nh'):
rho=0.90
STFTalpha=1/winSize # alpha in STFT approaches (for Gaussian derivative alpha=1)
sigmaS=(winSize-1)/4 # Sigma for STFT Gaussian window (applied if freqestim==2)
sigmaA=8/(winSize-1) # Sigma for Gaussian derivative quadrature filters (applied if freqestim==3)
convmode='valid' # Compute descriptor responses only on part that have full neigborhood. Use 'same' if all pixels are included (extrapolates np.image with zeros).
img=np.float64(img) # Convert np.image to double
r=(winSize-1)/2 # Get radius from window size
x=np.arange(-r,r+1)[np.newaxis] # Form spatial coordinates in window
if freqestim==1: # STFT uniform window
# Basic STFT filters
w0=np.ones_like(x)
w1=np.exp(-2*np.pi*x*STFTalpha*1j)
w2=np.conj(w1)
## Run filters to compute the frequency response in the four points. Store np.real and np.imaginary parts separately
# Run first filter
filterResp1=convolve2d(convolve2d(img,w0.T,convmode),w1,convmode)
filterResp2=convolve2d(convolve2d(img,w1.T,convmode),w0,convmode)
filterResp3=convolve2d(convolve2d(img,w1.T,convmode),w1,convmode)
filterResp4=convolve2d(convolve2d(img,w1.T,convmode),w2,convmode)
# Initilize frequency domain matrix for four frequency coordinates (np.real and np.imaginary parts for each frequency).
freqResp=np.dstack([filterResp1.real, filterResp1.imag,
filterResp2.real, filterResp2.imag,
filterResp3.real, filterResp3.imag,
filterResp4.real, filterResp4.imag])
## Perform quantization and compute LPQ codewords
inds = np.arange(freqResp.shape[2])[np.newaxis,np.newaxis,:]
LPQdesc=((freqResp>0)*(2**inds)).sum(2)
## Switch format to uint8 if LPQ code np.image is required as output
if mode=='im':
LPQdesc=np.uint8(LPQdesc)
## Histogram if needed
if mode=='nh' or mode=='h':
LPQdesc=np.histogram(LPQdesc.flatten(),range(256))[0]
## Normalize histogram if needed
if mode=='nh':
LPQdesc=LPQdesc/LPQdesc.sum()
print LPQdesc
return LPQdesc