|
以下转自平常心的博客:
前一段时间看到一篇文章"利用Matlab提取图图片中的数据",觉得思路挺好,遂下载下来研究了一番,发现作者所编写的程序没有考虑原始图片非水平放置的情况,而实际扫描图片时,将图片完全放置水平难度较大... 同时作者也没有考虑对数坐标的情况,且程序GUI界面不太人性化,操作有点不习惯。因此借着作者良好意愿,对其程序进行了改进~
考虑一张非水平无变形的曲线图,现将其曲线数据取出来,步骤如下:
- 在坐标轴上取三点以定位坐标系。如图中红色点所示。
- 在曲线上选取若干个点,如图中蓝色点所示。
- 设定坐标轴选取点x和y的实际值。
- 选取坐标系类型。
- 变换。
- 保存数据。
- 数据后处理。
在变换过程中程序首先计算(xi,yi)到(x1,y1)和(x2,y2)所组成的y轴的距离Δx,同样的方法计算Δy,当然Δx和Δy是图片的像素值。接下来计算每个像素点所对应实际坐标值。对于线性x轴,比例系数为(Xmax-Xmin)/(sqrt((x1-x0)^2)+(y1-y0)^2),同样对于线性y轴,比例系数(Ymax-Ymin)/(sqrt((x0-x2)^2)+(y0-y2)^2)。这样即可求出每个点的实际坐标值
Xi=Δx *(Xmax-Xmin)/(sqrt((x1-x0)^2)+(y1-y0)^2)+Xmin
Yi=Δy *(Ymax-Ymin)/(sqrt((x0-x2)^2)+(y0-y2)^2)+Ymin
对数坐标的变换关系类似
Xi=10^(log10(Xmin)+Δx *(log10(Xmax)-log10(Xmin))/(sqrt((x1-x0)^2)+(y1-y0)^2))
Yi= 10^(log10(Ymin)+Δy *(log10(Ymax)-log10(Ymin))/(sqrt((x0-x2)^2)+(y0-y2)^2))
具体操作说明
1.导入图片。
2.定位坐标系。按del键可删除上一个点
3.定位曲线。
4.设置变换参数。
5.变换。单击[变换]按钮后,弹出变换后的结果。
6.保存数据。
7.数据后处理
导入数据,假定导入后变量名为test
在Matlab Command窗口中输入 x=test(:,1);y=test(:,2); cftool;弹出曲线拟合工具箱
创建数据集
拟合数据
程序流程
数据初始化程序段:
- handles.optMode='zoom';
- handles.linedata=[];
- handles.dataCount=0;
- handles.datah=[];
- handles.axesdata=[];
- handles.axesCount=0;
- handles.axesh=[];
- handles.newdata=[];
- himage=findobj('tag','axes1');
- axes(himage);
复制代码
选定图片程序段:
- [file,path]=uigetfile({'*.jpg','图片文件(*.jpg)';'*.*','所有文件'},'请选择待分析图片...');
- if ~isequal(file, 0)
- cd(path);
- set(handles.fileEdit,'String',[path file]);
- end
复制代码
导入图像程序段:
- handles.dataCount=0;
- handles.axesCount=0;
-
- image_temp=imread(get(handles.fileEdit,'string'));
- imshow(image_temp); %read and show
- handles.ximage=size(image_temp,2);
- handles.yimage=size(image_temp,1);
- guidata(hObject,handles);
- % 更新状态栏
- h=findobj('tag','edit7');
- set(h,'String',num2str(handles.dataCount));
- ZoomPB_Callback(hObject, eventdata, handles);
复制代码
点选取程序段:
- p=get(gca,'CurrentPoint');
- switch handles.optMode
- case ('pickdata')
- if p(end,1)>0&&p(end,1)<handles.ximage&&p(end,2)>0&&p(end,2)<handles.yimage
- handles.dataCount=handles.dataCount+1;
- handles.linedata(handles.dataCount,:)=p(end,1:2);
- set(handles.countEdit,'String',num2str(handles.dataCount));
- hold on;
- handles.datah(handles.dataCount,1)=plot(p(end,1),p(end,2),'b*');
- guidata(hObject, handles);
- end
- case ('pickaxes')
- if p(end,1)>0&&p(end,1)<handles.ximage&&p(end,2)>0&&p(end,2)<handles.yimage&&handles.axesCount<3
- handles.axesCount=handles.axesCount+1;
- handles.axesdata(handles.axesCount,:)=p(end,1:2);
- set(handles.countEdit,'String',num2str(handles.axesCount));
- hold on;
- handles.axesh(handles.axesCount,1)=plot(p(end,1),p(end,2),'r+');
- guidata(hObject, handles);
- end
- end
复制代码
点删除程序段:
- switch get(gcf,'CurrentKey')
- case('space')
- PickDataPB_Callback(hObject, eventdata, handles);
- case('z')
- ZoomPB_Callback(hObject, eventdata, handles);
- case('m')
- PanPB_Callback(hObject, eventdata, handles);
- case('delete')
- switch handles.optMode
- case ('pickdata')
- if(handles.dataCount>0)
- delete(handles.datah(handles.dataCount,1));
- handles.dataCount=handles.dataCount-1;
- set(handles.countEdit,'String',num2str(handles.dataCount));
- guidata(hObject, handles);
- end
- case ('pickaxes')
- if(handles.axesCount>0)
- delete(handles.axesh(handles.axesCount,1));
- handles.axesCount=handles.axesCount-1;
- set(handles.countEdit,'String',num2str(handles.axesCount));
- guidata(hObject, handles);
- end
- end
- end
复制代码
坐标轴定标及坐标变换:
- %提取坐标信息
-
- xmin=str2double(get(handles.xminEdit,'string'));
- xmax=str2double(get(handles.xmaxEdit,'string'));
- ymin=str2double(get(handles.yminEdit,'string'));
- ymax=str2double(get(handles.ymaxEdit,'string'));
-
- xType=get(handles.xTypePM,'value');
- yType=get(handles.yTypePM,'value');
- %数据分类整理
- tmpaxes=handles.axesdata;
- ct=6;
- [c,r]=max(tmpaxes(:,1));
- axesxP=tmpaxes(r,:);
- ct=ct-r;
- [c,r]=min(tmpaxes(:,2));
- axesyP=tmpaxes(r,:);
- ct=ct-r;
- originP=handles.axesdata(ct,:);
- Data=zeros(handles.dataCount,2);
- data_new=zeros(handles.dataCount,2);
- %起点归零和坐标调整
- for i=1:handles.dataCount
- Data(i,2)=det([originP-axesxP;handles.linedata(i,:)-axesxP])/norm(originP-axesxP);
- Data(i,1)=-det([originP-axesyP;handles.linedata(i,:)-axesyP])/norm(originP-axesyP);
- end
- switch xType
- case 1
- data_new(:,1)=Data(:,1)/pdist([originP;axesxP]); %坐标归一化
- data_new(:,1)=xmin+data_new(:,1)*(xmax-xmin); %数据还原
- case 2
- data_new(:,1)=Data(:,1)/pdist([originP;axesxP]); %坐标归一化
- data_new(:,1)=10.^(log10(xmin)+data_new(:,1)*(log10(xmax)-log10(xmin)));
- end
- switch yType
- case 1
- data_new(:,2)=Data(:,2)/pdist([originP;axesyP]);
- data_new(:,2)=ymin+data_new(:,2)*(ymax-ymin);
- case 2'
- data_new(:,2)=Data(:,2)/pdist([originP;axesyP]); %坐标归一化
- data_new(:,2)=10.^(log10(ymin)+data_new(:,2)*(log10(ymax)-log10(ymin))); %数据还原
- end
- figure(3);
- if xType==2
- if yType==2
- loglog(data_new(:,1),data_new(:,2),'b*');
- else
- semilogx(data_new(:,1),data_new(:,2),'b*');
- end
- else
- if yType==2
- semilogy(data_new(:,1),data_new(:,2),'b*');
- else
- plot(data_new(:,1),data_new(:,2),'b*');
- end
- end
- handles.newdata=data_new;
- guidata(hObject,handles);
复制代码
数据保存代码段:
- [file,path]=uiputfile({'*.txt','文本文件(*.txt)';'*.*','所有文件'},'请选择待分析图片...');
- if ~isequal(file, 0)
- idata=handles.newdata;
- save([path file],'idata','-ascii');
- end
复制代码 |
|