【试题汇总】图像处理职位面试题汇总(1)
Matlab编程部分
1. Matlab 中读、写及显示一幅图像的命令各是什么?
解:第一、Matlab中读图像函数是imread( )。imread 函数用于读入各种图像文件,其一般的用法为:[X,MAP]=imread(‘filename’,‘fmt’)
其中,X,MAP分别为读出的图像数据和颜色表数据,fmt为图像的格式,filename为读取的图像文件(可以加上文件的路径)。如: [X,MAP]=imread(’flowers.tif’,’tif’);比较读取二值图像,灰度图像,索引图像,彩色图像的X和MAP的特点。
第二、Matlab中读图像函数是imwrite( ),imwrite函数用于输出图像,其语法格式为: imwrite(X,map,filename,fmt)
按照fmt指定的格式将图像数据矩阵X和调色板map写入文件filename。
第三、Matlab中显示图像函数是imshow( ),imshow函数是最常用的显示各种图像的函数,其语法如:imshow(X,map)
其中X是图像数据矩阵,map是其对应的颜色矩阵,若进行图像处理后不知道图像数据的值域可以用[]代替map。
二进制(二值)图像显示方法,在MATLAB中一幅二值图像是uint8或双精度的,该矩阵仅包含0和1。如果希望工具箱中的函数能将图像理解为二进制的,那么所有数据都要是逻辑数据,必须对其进行设置(将所有数据标志均设置on).可以对数据利用“~”取反操作实现图像逆转即黑白反色。灰度图像的显示方法,正常情况下无需指定灰度图像的调色板格式。可以是使用imshow函数指定要显示灰度级数目,格式 imshow(I,n),n为指定的灰度级数目。用户也可以指定数据的范围,格式imshow(I,[low high])其中low 和high参数分别为数据数组的最小值和最大值。如果为空矩阵([]),那么imshow函数将自动进行数据标度。索引图像,imshow(x,map)对于x的每个个像素,imshow显示存储map中相应行的颜色。RGB图像的显示,它直接对颜色进行描述而不使用调色板,格式imshow(RGB)。 RGB(:,:,1) RGB(:,:,2) RGB(:,:,3)特殊显示,如多幅图像的显示,需要显示多幅图像时。可以使用figure语句,它的功能就是重新打开一个图像显示窗口.2. Matlab 与VC++混合编程有哪几种方式?解:Matlab与VC++混合编程主要有三种方式:Matlab引擎方式、Matlab编译器及COM组件。
第一种:Matlab引擎方式。Matlab引擎采用客户机/服务器(Client/Server)的方式,提供了一组Matlab API函数,通过调用这些函数实现以用程序进程之间的数据传递。VC程序作为前端客户机,向Matlab引擎传递命令和数据,并从Matlab引擎接受数据信息,实现动态通信。采用这种方法几乎能利用MATLAB全部功能,但是需要在机器上安装MATLAB软件,而且执行效率低,因此在实际应用中不采用这种方法,在软件开发中也不可行。
第二种:Matlab编译器。MATLAB Compiler可以将M语言函数文件自动转化产生独立应用程序或者软件组件,生成的组件或者独立应用程序可以与其他用户共享。使用MATLAB Compiler创建的独立应用程序或者软件组件能够完全脱离MATLAB环境。MATLAB Compiler能够显著的缩短桌面应用程序的开发时间,仅仅通过简单的指令就可以将M语言函数转变为独立的应用程序或者软件组件,然后将它们打包发布给最终用户。这里所指的利用M语言开发的MATLAB应用程序可以包括数学计算、图形应用和GUIDE开发的图形界面等,而最终用户根本不需要拥有MATLAB。
其特点:1、自动将M语言函数文件转换为可执行应用程序,脱离MATLAB环境2、简单易用的发布过程3、支持所有MATLAB的M语言特性,例如MATLAB对象、Java对象等等。4、支持大多数工具箱函数,允许将MATLAB基本算法免费发布使用强大功能。 5、用户可以利用MATLAB集成环境开发自己的算法原型和应用程序,然后利用MATLAB Compiler将开发的算法发布给最终用户,最终用户可以通过可执行应用程序或者软件组件应用开发完好的算法。用户在进行算法维护的时候无需针对C代码进行操作。
算法开发仅仅需要三个步骤:第一步:创建算法,MATLAB本身是一种集成化的算法开发环境,它提供了各种工具用于完成算法快速原型的开发、测试。其中包括了高级的基于矩阵运算的向量化算法语言M语言,并且内建了大量用于数学计算、数据分析和图形可视化的算法函数。MATLAB开发工具提供了语言编辑器、调试工具和性能分析器,并且可以利用交互式图形界面开发工具开发自定义的图形界面工具。第二步:转化应用程序。使用MATLAB Compiler可以将开发好的M语言算法函数转变成为:独立可执行应用程序;C/C++算法共享库;软件组件,例如COM对象或者Excel插件;独立可执行应用程序;MATLAB Compiler可以自动地将MATLAB应用程序转变为独立可执行应用程序;自动确定相关的MATLAB函数 ;生成C/C++接口代码文件 ;将所有相关的文件打包压缩保存在单一压缩文件中;可在最终的应用程序中集成用户的C或C++代码。第三步:算法函数库。使用与创建独立可执行应用程序相同的指令就可以创建MATLAB函数库。MATLAB Compiler将自动创建相应的头文件和共享库文件,以便集成自定义的C/C++代码文件,最终完成应用程序的开发。通过MATLAB Compiler完成应用程序的发布之后,可以将应用程序打包、发布给任意的最终用户。MATLAB Compiler提供了相应的应用软件可以将运行应用程序必需的库文件打包。
第三种:COM组件。COM(Component Object Model,组件对象模型)是以组件为发布单元的对象模型,是一系列面向对象技术和工具的集合。由于COM是建立在二进制级别上的规范,所以组件对象之间的交互规范不依赖于任何特定的语言。MATLAB提供了COM生成器。COM生成器提供了实现MATLAB独立应用的一种新途径。它能把MATLAB开发的算法做成组件,这些组件作为独立的COM对象,可以直接被C++、VB、VC、C#、JAVA或其他支持COM的语言所引用,只要相应的MATLAB编译器和C/C+ +编译器都已经安装及配置成功,MATLAB COM编译器即可开始使用,并不需要特别的设置。该方法实现简单,通用性强,而且几乎可以使用MATLAB的任何函数(注意:不支持脚本文件,脚本文件使用时要改为函数文件),因此在程序较大、调用工具箱函数或调用函数较多时推荐使用。Matlab的COM 编译器是在Matlab6.5中才开始提供的一个新工具,从Matlab7.0起,这个产品改名为MatlabBuilder for COM。基于COM的混合编程方法也是Mathworks公司推荐使用的方法。
以上3种方法中,采用Matlab引擎方式,应用程序整体性能好,Matlab引擎支持功能全面,但需要Matlab后台运行,不能脱离Matlab 环境。而MCC方法和COM组件方法均可以脱离Matlab环境,应用程序运行效率高,利于软件的开发。
Prewitt算子、Roberts算子相比因此效果更好。Sobel算子包含两组3x3的矩阵,分别为横向及纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。缺点是Sobel算子并没有将图像的主题与背景严格地区分开来,换言之就是Sobel算子并没有基于图像灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。
Isotropic Sobel算子 Sobel算子另一种形式是(Isotropic Sobel)算子,加权平均算子,权值反比于邻点与中心点的距离,当沿不同方向检测边缘时梯度幅度一致,就是通常所说的各向同性Sobel(Isotropic Sobel)算子。模板也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。Roberts算子 罗伯茨算子、Roberts算子是一种最简单的算子,是一种利用局部差分算子寻找边缘的算子,他采用对角线方向相邻两象素之差近似梯度幅值检测边缘。检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。1963年,Roberts提出了这种寻找边缘的算子。Roberts边缘算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,边缘定位较准,对噪声敏感。适用于边缘明显且噪声较少的图像分割。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分析,由于Robert算子通常会在图像边缘附近的区域内产生较宽的响应,故采用上述算子检测的边缘图像常需做细化处理,边缘定位的精度不是很高。Prewitt算子 Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。经典Prewitt算子认为:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。Prewitt算子对噪声有抑制作用,抑制噪声的原理是通过像素平均,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位不如Roberts算子。因为平均能减少或消除噪声,Prewitt梯度算子法就是先求平均,再求差分来求梯度。该算子与Sobel算子类似,只是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检测图像边缘Laplacian算子Laplace算子是一种各向同性算子,二阶微分算子,在只关心边缘的位置而不考虑其周围的象素灰度差值时比较合适。Laplace算子对孤立象素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图象。存在噪声情况下,使用Laplacian算子检测边缘之前需要先进行低通滤波。所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。拉普拉斯算子也是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数。拉式算子用来改善因扩散效应的模糊特别有效,因为它符合降制模型。扩散效应是成像过程中经常发生的现象。Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;最后Laplacian算子不能检测边缘的方向;所以Laplacian在分割中所起的作用包括:(1)利用它的零交叉性质进行边缘定位;(2)确定一个像素是在一条边缘暗的一面还是亮的一面;一般使用的是高斯型拉普拉斯算子(Laplacian of a Gaussian,LoG),由于二阶导数是线性运算,利用LoG卷积一幅图像与首先使用高斯型平滑函数卷积改图像,然后计算所得结果的拉普拉斯是一样的。所以在LoG公式中使用高斯函数的目的就是对图像进行平滑处理,使用Laplacian算子的目的是提供一幅用零交叉确定边缘位置的图像;图像的平滑处理减少了噪声的影响并且它的主要作用还是抵消由Laplacian算子的二阶导数引起的逐渐增加的噪声影响。Canny算子Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘。边缘提取的基本问题是解决增强边缘与抗噪能力间的矛盾,由于图像边缘和噪声在频率域中同是高频分量,简单的微分提取运算同样会增加图像中的噪声,所以一般在微分运算之前应采取适当的平滑滤波,减少噪声的影响。Canny运用严格的数学方法对此问题进行了分析,推导出由# 个指数函数线性组合形式的最佳边缘提取算子网,其算法的实质是用一个准高斯函数作平滑运算,然后以带方向的一阶微分定位导数最大值,Canny算子边缘检测是一种比较实用的边缘检测算子,具有很好的边缘检测性能。Canny边缘检测法利用高斯函数的一阶微分,它能在噪声抑制和边缘检测之间取得较好的平衡。Laplacian of Gaussian(LoG)算子 利用图像强度二阶导数的零交叉点来求边缘点的算法对噪声十分敏感,所以,希望在边缘增强前滤除噪声.为此,将高斯滤波和拉普拉斯边缘检测结合在一起,形成LoG(Laplacian of Gaussian, LoG)算法,也称之为拉普拉斯高斯算法.LoG边缘检测器的基本特征是: 平滑滤波器是高斯滤波器.增强步骤采用二阶导数(二维拉普拉斯函数).边缘检测判据是二阶导数零交叉点并对应一阶导数的较大峰值.使用线性内插方法在子像素分辨率水平上估计边缘的位置.这种方法的特点是图像首先与高斯滤波器进行卷积,这一步既平滑了图像又降低了噪声,孤立的噪声点和较小的结构组织将被滤除.由于平滑会导致边缘的延展,因此边缘检测器只考虑那些具有局部梯度最大值的点为边缘点.这一点可以用二阶导数的零交叉点来实现.拉普拉斯函数用作二维二阶导数的近似,是因为它是一种无方向算子.为了避免检测出非显著边缘,应选择一阶导数大于某一阈值的零交叉点作为边缘点.5. 简述BP神经网络,AdBoost的基本原理?解:BP神经网络模型处理信息的基本原理是:输入信号Xi通过中间节点(隐层点)作用于输出节点,经过非线形变换,产生输出信号Yk,网络训练的每个样本包括输入向量X和期望输出量t,网络输出值Y与期望输出值t之间的偏差,通过调整输入节点与隐层节点的联接强度取值Wij和隐层节点与输出节点之间的联接强度Tjk以及阈值,使误差沿梯度方向下降,经过反复学习训练,确定与最小误差相对应的网络参数(权值和阈值),训练即告停止。此时经过训练的神经网络即能对类似样本的输入信息,自行处理输出误差最小的经过非线形转换的信息。
AdBoost是一个广泛使用的BOOSTING算法,其中训练集上依次训练弱分类器,每次下一个弱分类器是在训练样本的不同权重集合上训练。权重是由每个样本分类的难度确定的。分类的难度是通过分类器的输出估计的。
C/C++部分1. 关键字static的作用是什么?解:1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数,它是一个本地的全局变量。3)在模块内,一个被声明为静态的函数只可被这一模块的它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
2. 嵌入式系统总是用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit3,第二消除a的 bit 3。在以上两个操作中,要保持其它位不变.解:
int putList(int k, map<int, map<int, int>* >& listData, map<int, int>* mapData){ int nFlag =0;if (0 == k && mapData->size() >= 5){ nFlag =1;//listData.put(mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >( mapData->size(), mapData));} if (1 == k && mapData->size() >= 3){ nFlag =1;//listData.put(2 * mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >(2* mapData->size(), mapData));} if (2 == k && mapData->size() >= 2){ nFlag =1 ;//listData.put(3 * mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >( 3*mapData->size(), mapData));} return nFlag;}map<int, int>* getList(int* count, int k, int num, int& nMaxCount){ map<int, map<int, int>* > listData;//= new map<int, map<int, int>*>(); map<int, int>* mapTemp = NULL; int flag = 0; int nRet = 0;for (int i = 1; i < num; i++){ if (count[i] > k && flag == 0){ flag = 1; mapTemp = new map<int, int>;//mapTemp.put(i, count[i]); mapTemp->insert(pair <int, int>( i, count[i]));} else if (count[i] > k && flag == 1) { //mapTemp.put(i, count[i]); mapTemp->insert(pair <int, int>( i, count[i]));if (13 == i){ if (count[14 - i] > k) { //mapTemp.put(14 - i, count[14 - i]); mapTemp->insert(pair <int, int>( 14 - i, count[14 - i]));nRet = putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} else { flag = 0; nRet=putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} } } else if (count[i] <= k && flag == 1){ flag = 0; nRet=putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} } if (listData.size() > 0){listData.rend();map<int, map<int, int>* >::iterator it = listData.begin();nMaxCount = (*it).first;map<int, int>* mapReturn = (*it).second;map<int, int>* maptemp;it++;for (; it!=listData.end(); it++){maptemp = (*it).second;delete maptemp;maptemp = NULL;}return mapReturn;}else return NULL; } int* GetLongeststr(int* array, int nCount, int& outCount, int MaxNum){int* count = new int[MaxNum+1]; memset(count, 0, MaxNum*sizeof(int));int nMaxLoop=0;int nMaxTemp;int nMax1Loop=0;int nMax2Loop=0;int nMax3Loop=0;int nMaxkey =0;for (int i = 0; i < nCount; i++){ if (array[i] < 1 || array[i] > MaxNum) return NULL; ++count[array[i]];}map<int, map<int, int>*> allList;map<int, int>* mapTemp = NULL; map<int, int>* map1Temp = NULL;map<int, int>* map2Temp = NULL;map<int, int>* map3Temp = NULL;for (int k = 0; k < 3; k++){ mapTemp = getList(count, k, MaxNum, nMaxTemp);if (NULL != mapTemp){ if (0 == k) {map1Temp = mapTemp;nMax1Loop = nMaxTemp;nMaxLoop=nMaxTemp;}else if (1 == k){if (nMaxTemp>=nMaxLoop){map2Temp = mapTemp;nMax2Loop = nMaxTemp;nMaxLoop = nMaxTemp;}else{delete mapTemp;mapTemp =NULL;}}else{if (nMaxTemp>=nMaxLoop){map3Temp = mapTemp;nMax3Loop = nMaxTemp;nMaxLoop = nMaxTemp;}else{delete mapTemp;mapTemp =NULL;}}} }delete[] count;count = NULL;if (nMaxLoop>0){if (nMaxLoop == nMax3Loop){nMaxkey = 3;mapTemp = map3Temp;}else if (nMaxLoop == nMax2Loop){nMaxkey = 2;mapTemp = map2Temp;}else{nMaxkey = 1;mapTemp = map1Temp;}outCount = nMaxLoop;int* result = new int[outCount]; int k; int nAllCount = 0;map<int, int>::iterator itorResult;for (itorResult = mapTemp->begin(); itorResult!=mapTemp->end(); itorResult++){k = itorResult->first;for (int j =0; j<nMaxkey; j++){result[nAllCount++] = k;cout << itorResult->first <<",";}}cout << endl;if (map1Temp!=NULL){delete map1Temp;map1Temp = NULL;}if (map2Temp!=NULL){delete map2Temp;map2Temp = NULL;}if (map3Temp!=NULL){delete map3Temp;map3Temp = NULL;}return result;}else {outCount = 0;return NULL;}}=====================================================================转载请注明出处:http://blog.csdn.net/songzitea/article/details/13335375=====================================================================