存档在 2017年10月

MacTeX下载镜像

2017年10月27日

http://mirrors.ustc.edu.cn/CTAN/systems/mac/mactex/

DataGridView绑定Ilist对象,出现IndexOutOfRangeException错误的解决方法

2017年10月24日

我是这样绑定DataGridVeiw的:

IList<Resource> resources = new List<Resource>();
Resource  resource = new Resource();
resources.Add(resource);
dataGridView.DataSource = resources;

在第一个模块中能正常使用,没有任何问题。但到了第二个模块,同样的语句,只要一点击DataGridView控件,马上就会跳出System.IndexOutOfRangeException异常,具体内容如下:

未处理 System.IndexOutOfRangeException
  Message="索引 -1 没有值。"
  Source="System.Windows.Forms"
  StackTrace:
       在 System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
       在 System.Windows.Forms.CurrencyManager.get_Current()
       在 System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e)
       在 System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred)
       在 System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick)
       在 System.Windows.Forms.DataGridView.OnCellMouseDown(HitTestInfo hti, Boolean isShiftDown, Boolean isControlDown)
       在 System.Windows.Forms.DataGridView.OnCellMouseDown(DataGridViewCellMouseEventArgs e)
       在 System.Windows.Forms.DataGridView.OnMouseDown(MouseEventArgs e)
       在 System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
       在 System.Windows.Forms.Control.WndProc(Message& m)
       在 System.Windows.Forms.DataGridView.WndProc(Message& m)
       在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       在 System.Windows.Forms.Application.Run(Form mainForm)
       在 KoalaStudio.ksRBAC.PrivilegeConfigTool.Program.Main()
       在 System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       在 System.Threading.ThreadHelper.ThreadStart()

而且比较可恶的是,抛出异常的地方竟然是在Program.cs里,指向

Application.Run(new FrmMain());

这让人怎么调试,试了N回,也没发现原因。
于是上网找了找,竟然真有解决的方法,其作者也并未解决这个问题,而是采取了折衷的方法,用了一个过渡组件来解决:

BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = resources;
dgvResource.DataSource = bindingSource;

问题可以解决,但又有了新的问题,因为使用了BindingSource,因此对与DataGridView的更改并不能同步到Ilist对象上,所以还是不能用这种方法,继续研究。

上国外的网站看了看,终于找到了问题的原因,在向DataGridView绑定Ilist类型的对象是,如果对象的成员为0,那么就会出现
此问题。而且即使重新绑定DataGridView的数据源,也会继续存在此问题,解决的方法就是在向DataGridView绑定Ilist对象是,要保证其中至少有一个成员,否则宁可不绑定(虽然不是最完美的解决方法)。
其实最好的方法,是用BindingList对象代替Ilist对象作为DataGridView的数据源,即可彻底解决此问题,而且能实现DataGridView修改时与数据源的自动更新。但现在没有时间,只能先这样用了。

机器学习: Canonical Correlation Analysis 典型相关分析

2017年10月16日

Canonical Correlation Analysis(CCA)典型相关分析也是一种常用的降维算法。我们知道,PCA(Principal Component Analysis) 主分量分析将数据从高维映射到低维空间同时,保证了数据的分散性尽可能地大, 也就是数据的方差或者协方差尽可能大。而LDA(Linear Discriminant Analysis) 线性判别分析则利用了类标签,利用一种监督学习的方法,将数据从高维空间映射到低维空间时,让不同类的数据尽可能地分开而同一类的数据尽可能地聚合。

但是,有的时候,想知道多个线性空间之间的相关性。比如有的时候我们会从图像中提取各种特征,每一种特征都可以构成一个线性空间,为了分析这些空间之间的相关性,我们可以利用CCA 来做分析。
假设我们有两个特征空间,\(S1={\mathbf{x}_{1} \in R^{d1}}\)\(S2={\mathbf{x}_{2} \in R^{d2}}\)

\(\mathbf{x} = \begin{pmatrix}
\mathbf{x}_{1} \\
\mathbf{x}_{2}
\end{pmatrix}
\quad E(\mathbf{x}) = \begin{pmatrix}
\mathbf{\mu}_{1} \\
\mathbf{\mu}_{2}
\end{pmatrix}
\quad \Sigma = \begin{pmatrix}
\Sigma_{11} & \Sigma_{12} \\
\Sigma_{21} & \Sigma_{22}
\end{pmatrix}\)

可以看到,\(\Sigma_{12}=\Sigma_{21}^{T}\),\(\Sigma\) 称为协方差矩阵。我们引入投影向量 \(\mathbf{a}\), \(\mathbf{b}\), 假设投影之后的变量满足:

\(u=\mathbf{a}^{T} \mathbf{x}_{1} \quad v=\mathbf{b}^{T} \mathbf{x}_{2}\)

可以进一步算出 \(u,v\)的方差和协方差:

\(\text{var}(u)= \mathbf{a}^{T} \Sigma_{11} \mathbf{a}, \quad \text{var}(v)=\mathbf{b}^{T} \Sigma_{21} \mathbf{b}, \quad cov(u,v)=\mathbf{a}^{T} \Sigma_{12} \mathbf{b}\)

可以计算出 \(u,v\)的相关系数:

\(Corr(u,v)=\frac{\text{cov}(u,v)}{\sqrt{\text{var}(u)} \sqrt{\text{var}(v)}}\)

将u,v的表达式代入,可以得到:

\(Corr(u,v)=\frac{\mathbf{a}^{T} \Sigma_{12} \mathbf{b}}{\sqrt{\mathbf{a}^{T} \Sigma_{11} \mathbf{a}} \sqrt{\mathbf{b}^{T} \Sigma_{22} \mathbf{b}}}\)

我们的目标是让相关系数\(Corr(u,v)\)尽可能地大。为了求解\(\mathbf{a}\), \(\mathbf{b}\), 可以固定分母而让分子最大化,所以上面的函数可以变成:

\(\max_{\mathbf{a}, \mathbf{b}} \mathbf{a}^{T} \Sigma_{12} \mathbf{b}\)

构造拉格朗日等式:

\(L=\mathbf{a}^{T} \Sigma_{12} \mathbf{b}-\frac{\lambda_{1}}{2}(\mathbf{a}^{T} \Sigma_{11} \mathbf{a}-1)-\frac{\lambda_{2}}{2}(\mathbf{b}^{T} \Sigma_{22} \mathbf{b}-1)\)

L 分别对\(\mathbf{a}\), \(\mathbf{b}\)求导,可以得到:

\(\frac{\partial L}{\partial \mathbf{a}}= \Sigma_{12} \mathbf{b}- \lambda_{1} \Sigma_{11} \mathbf{a}=0\)

\(\frac{\partial L}{\partial \mathbf{b}}= \Sigma_{21} \mathbf{a}- \lambda_{2} \Sigma_{22} \mathbf{b}=0\)

根据约束条件,可以得到:

\(\lambda_{1}=\lambda_{2}=\mathbf{a}^{T} \Sigma_{12} \mathbf{b}\)

所以只要求出\(\lambda_{1}\) 或者\(\lambda_{2}\)就可以得到最大的相关系数。令\( \lambda=\lambda_{1}=\lambda_{2}\).
通过上面的偏导数,我们可以得到:

\(\Sigma_{11}^{-1}\Sigma_{12} \mathbf{b}= \lambda \mathbf{a}\)

\(\Sigma_{22}^{-1}\Sigma_{21} \mathbf{a}= \lambda \mathbf{b}\)

写成矩阵形式:

\(\begin{pmatrix}
\Sigma_{11}^{-1} & 0 \\
0 & \Sigma_{22}^{-1}
\end{pmatrix} \begin{pmatrix}
0 & \Sigma_{12} \\
\Sigma_{21} & 0
\end{pmatrix} \begin{pmatrix}
\mathbf{a} \\
\mathbf{b}
\end{pmatrix}=\lambda \begin{pmatrix}
\mathbf{a} \\
\mathbf{b}
\end{pmatrix}\)

令:

\(B= \begin{pmatrix}
\Sigma_{11} & 0 \\
0 & \Sigma_{22} \end{pmatrix}, \quad A= \begin{pmatrix}
0 & \Sigma_{12} \\
\Sigma_{21} & 0
\end{pmatrix} \quad \mathbf{w}=\begin{pmatrix}
\mathbf{a} \\
\mathbf{b}
\end{pmatrix}\)

那么,上式可以表示成:

\(B^{-1}A\mathbf{w}=\lambda \mathbf{w}\)

所以,\(\lambda \)和 \(\mathbf{w}\) 就是\(B^{-1}A\) 的特征值和特征向量。我们可以求出 \(B^{-1}A\)的特征值和特征向量,然后利用特征向量将原来的特征
\(\mathbf{x}_{1}, \mathbf{x}_{2}\)做映射。对应特征值 \(\lambda \)的求解,可以有更简单的方法,从上面的偏导数,我们可以得到如下等式:

\(\Sigma_{11}^{-1}\Sigma_{12}\Sigma_{22}^{-1}\Sigma_{21} \mathbf{a}=\lambda^{2} \mathbf{a}\)

我们可以利用上面的表达式求出\(\lambda \) 和 \(\mathbf{a}\),然后再待会上面的偏导数等式求出 \(\mathbf{b}\).
\(\lambda \)就是 \(u,v\)的相关系数,\(u,v\) 就是一对典型变量(canonical variables)。按照 \(B^{-1}A\) 的特征值从大到小排列,可以求出一系列的典型变量。特征值越大,说明典型变量的相关性越强。
Reference:
http://blog.csdn.net/wenyusuran/article/details/35290683

PCA and Whitening

2017年10月14日

文献:http://ufldl.stanford.edu/wiki/index.php/Exercise:PCA_and_Whitening

(一):数据准备

UFLDL下载的文件中,包含数据集IMAGES_RAW,它是一个512*512*10的矩阵,也就是10幅512*512的图像,可以看下其中的第二幅,使用extract_show函数。

function extract_show(IMAGESr, index)
%load IMAGES_RAW;
IMAGES_ = IMAGESr;
imshow(IMAGES_(:,:,index));

FE957034-C785-4284-B361-2B0100D32847

(1)载入数据

利用sampleIMAGESRAW函数,从IMAGES_RAW中提取numPatches个图像块,每个图像块大小为patchSize,并将提取到的图像块按列存放,分别存放在在矩阵patches的每一列中,即patches(:,i)存放的是第i个图像块儿的所有像素值。如下为产生的原始图像部分。
1

(2)数据去均值化处理

将每一个图像块儿的所有像素值都减去该图像块儿的平均像素值,实现数据的去均值化。
这里要注意一下第三行。理论上应该使用第二行做均值归0,但是图像每个像素点之间是很相关的。

[dim,sampleN] = size(x);%维数与样本数
%x = x - repmat(mean(x,2),1,sampleN);%标准PCA均值归0
x = x - repmat(mean(x,1),dim,1);

2

(二)PCA处理

该部分分为两部分:

(1)进行PCA计算

这里仅仅对数据x进行旋转得到xrot,而不进行主成分的提取,具体地:
①计算数据x的协方差矩阵sigma
②对sigma进行特征分解,利用matlab的eig函数,从而得到sigma的特征向量构成的矩阵U

[U,S,V]=eig(sigma);

U=[u1,…,ui,…,un],它的每一列分别是sigma的特征向量,n是输入数据的特征维数,S=diag([λ1,…λi,…,λn])是由sigma的特征值作为对角元素的对角阵,ui和λi相对应,为了后续的计算,这里要将U的各列次序进行调换,使得调换后的各列所对应的特征值大小依次递减,调换后的矩阵仍记作U,相应的特征值对角阵仍即为S,即:

U=[u1,...,ui,...,un],S=diag([λ1,...λi,...,λn])

满足:

λ1&gt;=...&gt;=λi&gt;=...&gt;=λn

③利用矩阵U对数据x进行旋转,得到xrot,即

xrot=U‘*x

完整代码如下:

xRot = zeros(size(x)); % You need to compute this 144 * 10000
S = x*x'/sampleN; %协方差矩阵
[U,D] = eig(S); %特征向量与特征值
U = fliplr(U);%U为列特征向量,D为特征值对角阵
D = fliplr(fliplr(D)'); %按照特征值由大到小排列
xRot = U'*x;

旋转变换后图为
3

(2)对旋转后的数据求解协方差矩阵covar

将协方差矩阵可视化,观察得到的选择后的数据是否正确。PCA保证选择后的数据的协方差矩阵是一个对角阵,如果covar是正确的,那么它的图像应该是一个蓝色背景,并且在对角线位置有一斜线。这里显示协方差矩阵covar利用了matlab的imagesc,imagesc(covar)的作用是:把矩阵covar以图像形式显示出来,矩阵中不同的数值会被赋予不同的颜色,得到的协方差矩阵的图像如下:可以看到,图像除了对角线位置外,其余部分颜色都相同。

covar = zeros(size(x, 1)); % You need to compute this
% Visualise the covariance matrix. You should see a line across the
% diagonal against a blue background.
covar = xRot*xRot';%获得变换后数据的协方差矩阵

4

(三)获取满足条件的主成分

本部分,找到满足条件的主成分的个数k,也就是找到最小的k值,使得(λ1+…+ λk)/(λ1+…+ λn)>某个百分数,如99%

k = 0; % Set k accordingly
var_total = sum(D(:))               %总方差
var_cur = 0;                        %方差计数
for k = 1:dim
    var_cur = var_cur + D(k,k);     %累计
    if (var_cur / var_total) &gt; 0.90 %如果能量已&gt;90%,则跳出for语句
        break;
    end
end

(四)利用找到的主成分个数,对数据进行降维

在第三步,已经找到了数字k,也就是,保留数据的k个主成分就满足了要求。在该步,将对数据x进行降维,只留下k个主成分。同时,为了观察降维后的数据的好坏,在利用U(:,k)将降维后的数据变换会原来的维数,也就是得到了原数据的近似恢复数据。并利用网格将恢复出的图像显示出,与原图像进行比较,下面第一幅图是由降维后的图像恢复出的原数据,下图是相应的原数据,可以发现,降维后的数据基本可以恢复出于原数据非常相近的数据。

xHat = zeros(size(x));  % You need to compute this
U_reduce = zeros(dim);          %初始化
U_reduce(:, 1:k) = U(:, 1:k);   %去掉特征值小的特征向量(降维)
y = U_reduce'*x;                %变换
xHat = U_reduce*y;              %反变换回来

% Visualise the data, and compare it to the raw data
% You should observe that the raw and processed data are of comparable quality.
% For comparison, you may wish to generate a PCA reduced image which
% retains only 90% of the variance.

figure('name',['#5 PCA processed images ',sprintf('(%d / %d dimensions)', k, size(x, 1)),'']);
display_network(xHat(:,randsel));
figure('name','Raw images');
display_network(x(:,randsel));

5
1
假如保存前90%的能量,PCA可以用44个特征代表144个特征。

(五)PCA白化+正则化

该部分分为两步

(1)执行具有白化和正则化的PCA

首先,对数据进行旋转(利用特征矩阵U),然后,利用特征值对旋转后的数据进行缩放,实现白化。同时,在利用特征值缩放时,利用参数ε对特征值进行微调,实现正则化。

epsilon = 0.1;
xPCAWhite = zeros(size(x));

eig_value = diag(D);                            %特征值
normalize = sqrt(eig_value+epsilon);            %白化系数
xPCAWhite = U'*x ./ (normalize*ones(1,sampleN));%白化

271631124694609

(2)计算白化后的数据的协方差矩阵,观察该协方差矩阵

如果加入了正则化项,则该协方差矩阵的对角线元素都小于1,如果没有加入正则项(即仅有旋转+白化),则该协方差矩阵的对角线元素都为1(实际上,是令ε为一个极小的数),下图是白化后数据的协方差矩阵对应的图像,上图是加入正则化后的结果,下图是没有加入正则化后的结果。

covar = xPCAWhite*xPCAWhite' / sampleN; %协方差矩阵 
figure('name','Visualisation of covariance matrix');
imagesc(covar);

8

(六)ZCA白化

ZCA白化,就是在PCA白化的基础上做了一个旋转,即

xZCAWhite = zeros(size(x));
xZCAWhite = U * xPCAWhite;  %ZCA白化 

271923492655269
下面的第一幅图是ZCA白化后的结果图,第二幅图是相应的原始图像。可以看到,ZCA白化的结果图似乎是原始图像的边缘。
white
1

Stanford UFLDL教程 MATLAB Modules

2017年10月14日

MATLAB Modules

Sparse autoencoder |sparseae_exercise.zip

  • checkNumericalGradient.m – Makes sure that computeNumericalGradient is implmented correctly
  • computeNumericalGradient.m – Computes numerical gradient of a function (to be filled in)
  • display_network.m – Visualizes images or filters for autoencoders as a grid
  • initializeParameters.m – Initializes parameters for sparse autoencoder randomly
  • sampleIMAGES.m – Samples 8×8 patches from an image matrix (to be filled in)
  • sparseAutoencoderCost.m -Calculates cost and gradient of cost function of sparse autoencoder
  • train.m – Framework for training and testing sparse autoencoder

Using the MNIST Dataset |mnistHelper.zip

  • loadMNISTImages.m – Returns a matrix containing raw MNIST images
  • loadMNISTLabels.m – Returns a matrix containing MNIST labels

PCA and Whitening |pca_exercise.zip

  • display_network.m – Visualizes images or filters for autoencoders as a grid
  • pca_gen.m – Framework for whitening exercise
  • sampleIMAGESRAW.m – Returns 8×8 raw unwhitened patches

Softmax Regression |softmax_exercise.zip

  • checkNumericalGradient.m – Makes sure that computeNumericalGradient is implmented correctly
  • display_network.m – Visualizes images or filters for autoencoders as a grid
  • loadMNISTImages.m – Returns a matrix containing raw MNIST images
  • loadMNISTLabels.m – Returns a matrix containing MNIST labels
  • softmaxCost.m – Computes cost and gradient of cost function of softmax
  • softmaxTrain.m – Trains a softmax model with the given parameters
  • train.m – Framework for this exercise

from: http://ufldl.stanford.edu/wiki/index.php/MATLAB_Modules

人脸图像的几何归一化和灰度归一化

2017年10月13日

在对人脸表情进行识别时,人脸的归一化处理是至关重要的一环,它涉及到下一步处理的好坏。
人脸的归一化包括几何归一化和灰度归一化,几何归一化分两步:人脸校正和人脸裁剪。而灰度归
一化主要是增加图像的对比度,进行光照补偿。
1.几何归一化
几何归一化的目的主要是将表情子图像变换为统一的尺寸,有利于表情特征的提取。具体步骤如下:
(1)标定特征点,这里用[x,y] = ginput(3)函数来标定两眼和鼻子三个特征点。主要是用鼠标动手标
定,获取三个特征点的坐标值。
(2)根据左右两眼的坐标值旋转图像,以保证人脸方向的一致性。设两眼之间的距离为d,其中点为O。
(3)根据面部特征点和几何模型确定矩形特征区域,以O为基准,左右各剪切d,垂直方向各取0.5d和
1.5d的矩形区域进行裁剪。
(4)对表情子区域图像进行尺度变换为统一的尺寸,更有利于表情特征的提取。把截取的图像统一规格
为90*100的图像,实现图像的几何归一化。
面部几何模型如下图:
20130709122421625
2.灰度归一化
灰度归一化 主要是增加图像的亮度,使图像的细节更加清楚,以减弱光线和光照强度的影响。
这里用的是image=255*imadjust(C/255,[0.3;1],[0;1]); 用此函数进行光照补偿。
具体代码如下:

C= imread('Image001.jpg');
figure(1),imshow(C);
C=double(C);
image=255*imadjust(C/255,[0.3;1],[0;1]);
figure(2),imshow(image/255);
title('Lighting compensation');%光照补偿

[x,y] = ginput(3);    %%1 left eye, 2 right eye, 3 top of nose
cos = (x(2)-x(1))/sqrt((x(2)-x(1))^2+(y(2)-y(1))^2);
sin = (y(2)-y(1))/sqrt((x(2)-x(1))^2+(y(2)-y(1))^2);
mid_x = round((x(1)+x(2))/2);
mid_y = round((y(2)+y(1))/2);
d = round(sqrt((x(2)-x(1))^2+(y(2)-y(1))^2));
rotation = atan(sin./cos)*180/pi;
img = imrotate(image,rotation,'bilinear','crop'); 
figure(3), imshow(img);%人脸校正

[h,w] = size(img);
leftpad = mid_x-d;
if leftpad&lt;1
   leftpad = 1;
end
toppad =mid_y - round(0.5*d);
if toppad&lt;1
   toppad = 1;
 end
 rightpad = mid_x + d;
 if rightpad&gt;w
    rightpad = w;
 end
 bottompad = mid_y + round(1.5*d);
 if bottompad&gt;h
    bottompad = h;
 end   
 I1 =[];
 I2 =[];
 I1(:,:) = img(toppad:bottompad,leftpad:rightpad);
 I2(:,:) = imresize(I1,[90 100]); 
 figure(4),imshow(I2,[]);%人脸裁剪

matlab图像类型转换以及uint8、double、im2double、im2uint8和mat2gray等说明

2017年10月13日

1. matlab图像保存说明
matlab中读取图片后保存的数据是uint8类型(8位无符号整数,即1个字节),以此方式存储的图像称作8位图像,好处相比较默认matlab数据类型双精度浮点double(64位,8个字节),自然可以节省很大一部分存储空间。
详细来说imread把灰度图像存入一个8位矩阵,当为RGB图像时,就存入8位RGB矩阵中。例如,彩色图像像素大小是400*300( 高 * 宽 ),则保存的数据矩阵为400*300*3,其中每个颜色通道值是处于0~255之间。
但是虽然matlab中读入图像的数据类型是uint8,而在图像矩阵运算的时候,使用的数据类型却是double类型。一是为了保证精度,二是因为如果不转换,在对uint8进行加减时会产生溢出,可能提示的错误为:

Function ‘*’ is not defined for values of class ‘uint8’
1个字节无符号整型最大只能存储数据为255,对图片的操作所以很容易溢出。

2. matlab图像类型转换
matlab读入图像的数据是uint8,而matlab中数值一般采用double型(64位)存储和运算。所以要先将图像转为double格式的才能运算,区别如下:

img = imread('./1.jpg'); % 读入是unit8型(0~255)数据
I1  = im2double(img);    % 把图像转换成double精度类型(0~1)
I2  = double(img)/255;   % uint8转换成double,作用同im2double

这里补充说明一下,im2double( )和double( )的区别。double( img)就是简单的数据类型转换,将无符号整型转换为双精度浮点型double,但是数据大小没有变化,原本数据是0~255之间,转化后还是0~255。例如原来是255,那么转换后为255.0,小数位0个数是由double数据长度决定,实际数据大小还是255,只不过这个255已经是double类型空间存储了,再增加不会发生溢出情况。而im2double(img)则不仅仅是将uint8转换到double类型,而且把数据大小从0~255映射到0~1区间。
另外需要补充说明下面这种情况:

img = imread('./1.jpg');
I1  = double(img);
I2  = im2double(I2); % I2数据依然是0~255,并不是0~1,即I1=I2

因为I1已经是double类型,imdouble不会对double类型数据0~255映射到区间0~1,所以上面im2double操作没有任何作用,I1和I2相等。
总结如下:函数im2double将输入转换成double类型。如果输入是uint8、unit16 或者是二值的logical类型,则函数im2double 将其值归一化到0~1之间,当然就是double类型的了。如果输入本身就是double类型,输出还是double类型,并不进行映射。
如果已经是double类型的数据需要映射,则进行下面操作即可:

I2 = I1/255;
3. matlab图像显示imshow类型问题
在matlab处理完数据好,我们希望显示或者imwrite写入图片时候,需要注意。如果直接对double之间的数据矩阵I运行imshow(I),我们会发现有时候显示的是一个白色的图像。
这是因为imshow()显示图像时对double型是认为在0~1范围内,即大于1时都是显示为白色,而imshow显示uint8型时是0~255范围。所以对double类型的图像显示的时候,要么归一化到0~1之间,要么将double类型的0~255数据转为uint8类型。解决方法如下:

imshow(I/255);    % 将图像矩阵转化到0-1之间
imshow(I,[]);     % 自动调整数据的范围以便于显示
inshow(uint8(I)); % 转成uint8

4. uint和double数据转换的深入说明
double和uint8、uint16之间数据转换有下面的函数:

im2double(); % 将图像数组转换成double精度类型
im2uint8();  % 将图像数组转换成unit8类型 
im2uint16(); % 将图像数组转换成unit16类型

当然,当图像数据是double类型的0~1之间,下面两者操作是等价的:

I1=im2uint8(I); 
I2=uint8(round(I*255)); 

但是matlab默认double类型图片数据是位于0~1之间的,而uint8是位于0~255。所以如果矩阵数据图像是double类型(0~1之间)可直接im2uint8,这样不仅完成数据类型转换,而且将0~1之间映射为了0~255之间的数据。
但是如果图像矩阵数据是double类型的0~255,直接im2uint8转换的话,matlab会将大于1的数据都转换为255,0~1之间的数据才会映射到0~255之间整型的数据。例如下面程序:

img64 = [1,2,3,4];
I8    = im2uint8(img64); % I8结果为[255 255 255 255]

5. mat2gray()和im2double()区别
这两个如果都是对uint8数据操作,区别就在于前者是归一化操作,归一化后也在0~1之间,自然结果也是double类型,后者是将数据从0~255映射到0~1。例如:

I  = uint8([1,1,2,3]);
I1 = mat2gray(I);  % 归一化,I1结果是double型[0,0,0.5,1]
I2 = im2double(I); % 映射化,I2结果是double型[0.0039,0.0039,0.0078,0.0118]

可以看出,虽然两者都是一种归一化,im2double只不过最大值永远是常数255,最小值永远是0,如下:

(I−0.0)/(255.0−0.0)
而mat2gray最大值和最小值都是当前矩阵中最大最小的值,如下:
(I−min(I))/(max(I)−min(I))
另外补充一个函数,mat2str()是将数型转换为字符串类型,一般在批量处理图片,给保存图片格式的名称中有作用,这样就不需要格式化sprintf操作了,非常方便。

机器学习模型需要对数据进行归一化

2017年10月11日

1)归一化后加快了梯度下降求最优解的速度;2)归一化有可能提高精度

1 归一化为什么能提高梯度下降法求解最优解的速度?
如下图所示,蓝色的圈圈图代表的是两个特征的等高线。其中左图两个特征X1和X2的区间相差非常大,X1区间是[0,2000],X2区间是[1,5],其所形成的等高线非常尖。当使用梯度下降法寻求最优解时,很有可能走“之字型”路线(垂直等高线走),从而导致需要迭代很多次才能收敛;而右图对两个原始特征进行了归一化,其对应的等高线显得很圆,在梯度下降进行求解时能较快的收敛。因此如果机器学习模型使用梯度下降法求最优解时,归一化往往非常有必要,否则很难收敛甚至不能收敛。
192105553858119
2 归一化有可能提高精度
一些分类器需要计算样本之间的距离(如欧氏距离),例如KNN。如果一个特征值域范围非常大,那么距离计算就主要取决于这个特征,从而与实际情况相悖(比如这时实际情况是值域范围小的特征更重要)。
3 归一化的类型
1)线性归一化
76512b142c1b7e27e8a7e7eb1fc11225
这种归一化方法比较适用在数值比较集中的情况。这种方法有个缺陷,如果max和min不稳定,很容易使得归一化结果不稳定,使得后续使用效果也不稳定。实际使用中可以用经验常量值来替代max和min。

2)标准差标准化
  经过处理的数据符合标准正态分布,即均值为0,标准差为1,其转化函数为:
z-score-2
  其中μ为所有样本数据的均值,σ为所有样本数据的标准差。

3)非线性归一化
经常用在数据分化比较大的场景,有些数值很大,有些很小。通过一些数学函数,将原始值进行映射。该方法包括 log、指数,正切等。需要根据数据分布的情况,决定非线性函数的曲线,比如log(V, 2)还是log(V, 10)等。
源码示例(这里包含了三种方法:前两种是编程实现,最后一种直接调用MATLAB函数来实现):

oriImage = imread('XXXX.jpg');
grayImage = rgb2gray(oriImage);
figure;
imshow(grayImage);

originalMinValue = double(min(min(grayImage)));
originalMaxValue = double(max(max(grayImage)));
originalRange = originalMaxValue - originalMinValue;

% Get a double image in the range 0 to +255
desiredMin = 0;
desiredMax = 255;
desiredRange = desiredMax - desiredMin;
dblImageS255 = desiredRange * (double(grayImage) - originalMinValue) / originalRange + desiredMin;

figure;
imshow(uint8(dblImageS255));

% Get a double image in the range 0 to +1
desiredMin = 0;
desiredMax = 1;
desiredRange = desiredMax - desiredMin;
dblImageS1 = desiredRange * (double(grayImage) - originalMinValue) / originalRange + desiredMin;

figure;
imshow(dblImageS1);

% Another way to normalazation, which only calls MATLAB function
img3 = mat2gray(oriImage);
figure;
imshow(img3);