Matlab按照灰度图像去除数据冗余
之前处理数据,在范数阈值处理的时候,没想到出现了两个问题:1、没有考虑到图片的尺寸不同,用同一的阈值去处理图像是不合理的。2、norm函数并非原来认为的只是平方和然后开根号,这其实自己也是没有搞懂,以后搞懂了。在写。后面做了一定的修改。
clear;close all;clc; %% %由于程序运行的时间太长了,保存第一次运行的输出 % 程序开始执行 % 读取图片文件信息,并按类、视频序号、文件尺寸, % 存到结构体fileInfoPartition中,耗时:185.7336 % % 把结构体fileInfoPartition按阈值0.5为分割在结构体fileInfoResult % 共耗时:3017.0879 % % 拷贝简化后的数据共花费时间:54.1738 % % 拷贝冗余的数据共花费时间:230.4289 %% %程序如何操作: %变量pathSource为要处理的图片数据,所在的文件夹,就数字时间码识别而言。就是各个子分类0、1、2上一级文件夹 %变量pathTemp为保存灰度中变变量图像的文件夹 %变量pathDestination改为处理好数据保存的文件夹 %destinationFlag和redundanceFlag分别控制是否保存原始的数据和冗余数据 %% %下一步改进: %统计简化数据和冗余数据分别都有多少 %现在求的阈值是整体的二范数,没有考虑到图像尺寸的影响。下一步看二范数除以尺寸后再加阈值判断 %% %程序实现的功能 %1、先把彩色图像转换为灰度图像 %2、在灰度图像中,根据指定的路径、视频序号和差距系数,挑选出对应相同视频号的相同位置数字的冗余的 %3、把先前挑选出的灰度数据对应的彩色图像精简的保存在文件夹pathdestination、冗余数据保存在文件夹pathredundance %% %程序中用到的新功能:之前一直没用过结构体,现在用了结构体数组。 %参考程序decreaseRedundantColor %1)prod(A):数组内所有数字相乘,配合size挺好用的 %2)numel(A):返回矩阵中的所有元素个数,这个就可以替换上面的prod(size(A)),而且速度比它更快,这是matlab自动提示出来的 %3) %4) %5) %% %变量命名规则: %总路径下一层的文件夹记为dir(directory) %最后一层就是各个文件记为file %% %程序编程思路: %如果只考虑不过数据之间的差异性,而作差二范数,后阈值处理。这样存在颜色比较丰富的彩色图像,会保留更多。 %而颜色相对单调的图像,保留的数据更少。这不公平,而如果对于这两种图像采用不同的阈值,这又违反了科学的精神 %所以考虑到先都转化为灰度图像,然后用相同的阈值进行比较。这样来去除冗余数据,这样和之后肯定会进行的PCA处理,想呼应。 %这才是我目前认为最科学的数据处理方法 tic; disp('程序开始执行'); %%%%%%%%%%%%需要更改的参数%%%%%%%%%%%%%%%%%%%% %要处理的数据的源地址,里面有子文件夹0、1、2...9 pathSource='C:\Users\Dy\Desktop\彩色视频真实数据\sjz'; %保存中间数据灰度图像的文件夹 pathTemp='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr\tempGray'; %保存去冗余后数据的路径 pathDestination='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr'; %是否生成无冗余数据的标志符号,为0,不生成,非0生成 simplifyFlag=1; %是否生成冗余数据的标志符号,为0,不生成,非0生成 redundanceFlag=1; %判断数据,是否冗余的阈值,初步选为0.5 differentCriterion=0.16; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %先读取pathSource文件夹下存在的子文件,保存子文件夹信息。方便后面处理。 dirList=dir(pathSource);%读取文件夹列表,这种方式读取会保留原文件.(在结构体中第一个)和上一层目录..(在结构体第二个) countDir=length(dirList);%文件夹个数 tic; %先把彩色图像转换为灰度图像,放在文件夹pathTemp中,方便后面的比较图像 for numDir=3:countDir%先读取数据文件夹pathSource下的子文件夹 if(length(dirList(numDir).name)>=2)%根据这个过滤掉在此文件夹可能存在的各种txt文件 continue; end %为中间变量灰度图想创建保存数据的子文件 pathCreDir=[pathTemp,'\',dirList(numDir).name,'\']; mkdir(pathCreDir); fileList=dir([pathSource,'\',dirList(numDir).name]); countFile=length(fileList); disp(['正在转换子文件夹',dirList(numDir).name,'中的图像']); for numFile=3:countFile%依次读取所有的文件名 tempName=[pathSource,'\',dirList(numDir).name,'\',fileList(numFile).name];%依次得到具体图片文件的完整路径 temp=imread(tempName);%读入图片 graytemp=rgb2gray(temp);%彩色图像转化为灰度图像 %保存在和源文件一样的对应文件夹内,按同样的文件名、文件类型保存 imwrite(graytemp,[pathCreDir,fileList(numFile).name]); end disp(['共转换了',num2str(countFile-2),'张图片']) end disp(['把彩色图像转换为灰度图像,并保存在中间变量文件夹',pathTemp]); disp(['共耗时:',num2str(toc)]) %% %直接处理中间变量文件夹中的数据,然后按得到的结果从彩色图像源文件夹分割数据去冗余 %整体仿照文件decreaseRedundantColor.m编写 %提取出原始数据里面的有用数据保存到结构体中 %把文件的全部信息一次性全部先读取到一个结构体数组fileInfoRaw中来 % 结构体数字,第一维为类别(相对应子文件夹文件名加1),第二维为图片序号 % 结构体数组中有字段 % name:图片的名字 % videonum:图片来源于那个视频 % size:[图片的宽(竖直方向跨度),图片的长度(水平方向跨度)] tic; dirList=dir(pathTemp);%读取文件夹列表,这种方式读取会保留原文件.(在结构体中第一个)和上一层目录..(在结构体第二个) countDir=length(dirList);%文件夹个数 for numDir=3:countDir%先读取数据文件夹pathSource下的子文件夹 if(length(dirList(numDir).name)>=2)%根据这个过滤掉在此文件夹可能存在的各种txt文件 continue; end fileList=dir([pathTemp,'\',dirList(numDir).name]); countFile=length(fileList); for numFile=3:countFile%依次读取所有的文件名 %去除图片所属的视频序号 tempName=fileList(numFile).name; nameStart=strfind(tempName,'_'); nameEnd=strfind(tempName,'-'); tempVideoOrder=tempName(nameStart+1:nameEnd-1); tempPic=imread([pathTemp,'\',dirList(numDir).name,'\',fileList(numFile).name]); %tempSize=size(tempPic);%读取的当前图片的size %要注意提取出来的子文件的名称再加1得到了结构体的数据信息,而numFile是从第3开始的,所以要减2 fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).name=tempName; fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).videonum=str2double(tempVideoOrder); fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).size=size(tempPic); end end %读取出所有的视频序号 %读取第一个子文件中的视频数据(一般而言每个视频肯定都会生成数据0,所以读取0文件夹可以选出所有的视频序号的) [sumClasses,maxFile]=size(fileInfoRaw); videoList(1)={0};%cell中第一项填充一个0方面后续的程序编写。 %原本想去除所有的视频序号,然后用unique提取出唯一信息。 %但由于视频序号并不是统一规格的长短,所以只能用比较麻烦的方法。 % for numFile=1:maxFile % if ~isempty(fileInfoRaw(numFile).videonum) % videoList=[videoList;fileInfoRaw(numFile).videonum]; % end % end %读取第一个结构体,就是子文件夹0中的图片数量,挑选没有重复的数据 for numFile=1:maxFile %注意这里的fileInfoRaw(1,numFile),就是指定了子文件夹0中的数据,不能忘记这个1 if ~isempty(fileInfoRaw(1,numFile).videonum) countVideo=length(videoList); for tempVideoNum=1:countVideo if videoList{tempVideoNum} == fileInfoRaw(1,numFile).videonum continue; else %一开始没加这行,伤不起呀。必须是比较完videoList中所有的 %视频序号都没有相同的视频,才开始往videoList中添加 if tempVideoNum == countVideo %下面这种方式,对于cell的操作,每次videoList多生成一行 videoList=[videoList;fileInfoRaw(1,numFile).videonum]; end end end end end videoList=videoList(2:end);%删除第一项,得到了要处理的视频序号 sumVideo=length(videoList);%统计得到video的总数量 %由于要记录的信息太多,而又想不到能一步得到很多信息的方法。 %所以就把这些东西简单分为一小部分一小部分记录 %用二维结构体数组fileInfoSize保存图片的尺寸信息,第一维为类别,第二维为对应于videoList中相同位置的视频 %先用tempSize保存某一类,某一视频序号videoList{numVideo}下的所有的尺寸信息, %然后再把这些信息保存到结构体fileInfoSize中 %结构体数组中有字段 %size:保存着对应于行(类别),列(视频videoList{numVideo})的所有尺寸 for numClass=1:sumClasses%对应的类别 for numVideo=1:sumVideo%对应的视频序号 tempSize={[0,0,0]};%必须是cell,才能方便每次统计在某个类别下面对应视频的size总数 %下面这个for,就是判断指定类别,指定视频序号的所有尺寸的累加 for i=1:maxFile %因为结构体也是按最大尺寸,填充的,所以有一些是空的 %先判断,如果是空数据就不进行处理 if isempty(fileInfoRaw(numClass,i).videonum) break; %一次也就判断指定视频的尺寸,所以下面加入判断是对应的视频才处理 elseif videoList{numVideo}==fileInfoRaw(numClass,i).videonum countTempSize=length(tempSize); %选取到某一个文件信息,然后用tempSize中的所有尺寸信息和其比较,如果都不相同,在添加到tempSize中 for numTempSize=1:countTempSize %先用setdiff判断数组tempSize{numTempSize}和fileInfoRaw(numClass,i).size %是否相同,如果相同则返回空,正好用isempty判断 %下面一开始判断两个数组是否相等是只有语句isempty(setdiff(tempSize{numTempSize},fileInfoRaw(numClass,i).size)) %而这个函数为setdiff(a,b)只是返回b中没有的,a的值,那么遇到a=[17 17 3] %b=[17 15 3],则setdiff(a,b)返回空,所以用了下面这种加强的判断方法, %[setdiff(a,b),setdiff(b,a)]注意两个数组直接连接用的是逗号 %这样就可以两个数组直接是不是相等,完全判断 if isempty([setdiff(tempSize{numTempSize},fileInfoRaw(numClass,i).size),setdiff(fileInfoRaw(numClass,i).size,tempSize{numTempSize})]) %一开始这写为continue,这是错误的。因为上面的for是在整个tempSize里面 %找是否有相同的,有相同的就停止执行后面的else中的添加功能。 %如果改为continue了,反倒成了找tempSize中是否有和当前size中不同的数据 %如果有,就加进tempSize中。这相当蛋疼。哎,太菜了。 %不过也是之前没写过那么复杂的程序。。。。 break; else %又忘了加后面这个判断了,如果是所有的在tempSize中的尺寸都比较完之后 %还是没有发现和fileInfoRaw(numClass,i).size相同的数据,才往 %tempSize中添加新数据 if numTempSize == countTempSize tempSize=[tempSize;fileInfoRaw(numClass,i).size]; end end end end end %上面这个for,就取出了对应类别,对应视频的所有不同的尺寸,由于有个初始的[0,0,0] %所以去掉第一个初始值,从第二个开始 tempSize=tempSize(2:end); fileInfoPartition(numClass,numVideo).picSize=tempSize; end end %把每个类、每个视频中的所有的尺寸信息保存到了结构体fileInfoSize中, %在结构体fileInfoSize再加入sumSize这个字段来统计,对应结构体下各种多少种size的图像 for numClass=1:sumClasses%对应的类别 for numVideo=1:sumVideo%对应的视频序号 fileInfoPartition(numClass,numVideo).sumSize=size(fileInfoPartition(numClass,numVideo).picSize,1); end end %往结构体fileInfoPartition中添加字段nameList %nameList中有sumSize行,分别对应于picSize中各行的尺寸 %由于早已经把要处理的信息都保存在结构体fileInforRaw,所以只要读取里面的信息就可以了 %[sumClasses,maxFile]=size(fileInfoRaw); %sumVideo=length(videoList);%统计得到video的总数量 for numClass=1:sumClasses%对应的类别 for numVideo=1:sumVideo%对应的视频序号 for numSize=1:fileInfoPartition(numClass,numVideo).sumSize%遍历每个类别对应视频下的所有尺寸数据 tempName={'0'};%cell类型,方便统计最后的相同尺寸的文件的数量,可以存放不同类型的数据 for numFile=1:maxFile %由于结构体,会规整整个结构体的尺寸,所以要首先判断,当前结构体数字下的内容是否为空 if isempty(fileInfoRaw(numClass,numFile).videonum) %按顺序遍历整个结构体中的数据,如果发现空内容,所以当前分类的数据已经、 %遍历完,所以break,进入下一个类 break; elseif videoList{numVideo}==fileInfoRaw(numClass,numFile).videonum %上面先进行判断是不是属于这个视频的数据 %下面判断,是不是属于这个尺寸的数据 if isempty([setdiff(fileInfoPartition(numClass,numVideo).picSize{numSize},fileInfoRaw(numClass,numFile).size), ... setdiff(fileInfoRaw(numClass,numFile).size,fileInfoPartition(numClass,numVideo).picSize{numSize})]) tempName=[tempName;fileInfoRaw(numClass,numFile).name]; end end end %上面这个for为在某个类别,对应视频序号,按顺序的某个尺寸遍历完的所有文件名列表 tempName=tempName(2:end); %由于打算把计算出来的文件名列表保存按行(对应于结构体中picSize中的尺寸信息) %而这样文件名列表不同行(即不同尺寸)的文件数量是不相等的 %对于这种不同维度的数据,直接一行一行操作cell会出错,所以只能一个一个进行添加 sumName=length(tempName); for i=1:sumName fileInfoPartition(numClass,numVideo).nameList(numSize,i)=tempName(i); end %想到了反正都算出了了不同类别不同视频不同尺寸的文件数量 %那就把这个信息保存到结构体的字段picSizeCount中,每行都对应picSize中文件数量 fileInfoPartition(numClass,numVideo).picSizeCount(numSize,1)=sumName; end end end %读取文件信息,并按类、视频序号、文件名尺寸存到结构体fileInfoPartition中 disp('读取图片文件信息,并按类、视频序号、文件尺寸,'); disp(['存到结构体fileInfoPartition中,耗时:',num2str(toc)]); %% %终于把有用的信息都提取到了结构体fileInfoPartition中,结构体总共有10行(10个类别),n列(n个视频) %结构体有字段: %picSize:对应类(结构体行)和视频(结构体列)的数据的尺寸 %sumSize:对应类(结构体行)和视频(结构体列)的数据的各种尺寸的总数 %nameList:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件名列表 %picSizeCount:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件总数 %计划把判断是否冗余,计算好后的数据保存到结构体fileInfoResult中 %picSize:对应类(结构体行)和视频(结构体列)的数据的尺寸 %sumSize:对应类(结构体行)和视频(结构体列)的数据的各种尺寸的总数 %nameList:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件名列表 %和fileInfoPartition中数据相比是它的两倍的行数,相当于把fileInfoPartition中的每一行拆为两行,奇数行为冗余 %偶数行为对应的未冗余 %picSizePartitionCount:对应于namelist中各行的数据量 tic; %先把数据在新建的结构体中完成分割,然后再根据destinationFlag和redundanceFlag确定是否要写入分割的数据 %先整体扫描结构体中fileInfoPartition,计算出所有的是否冗余的信息,然后存到fileInfoResult中 % pathSource='C:\Users\Dy\Desktop\彩色视频真实数据\val2'; %[sumClasses,maxFile]=size(fileInfoRaw); %sumVideo=length(videoList);%统计得到video的总数量 %vainFlag:发现要添加一个vainFlag的标记来,取消掉某一个文件名的重复比较 %主要是考虑到每到一个文件名,都要计算后面所有的文件是否重复,这个计算量有点大。 %而且如果不添加这个flag,会导致比如重复图片中的最后一个图片会被添加到无冗余数据的列表中 for numClass=1:sumClasses%对应的类别 for numVideo=1:sumVideo%对应的视频序号 % if numVideo==3 % temp=1; % end for numSize=1:fileInfoPartition(numClass,numVideo).sumSize%遍历每个类别对应视频下的所有尺寸数据 %把字段picSize和sumSize也补上 fileInfoResult(numClass,numVideo).picSize=fileInfoPartition(numClass,numVideo).picSize; fileInfoResult(numClass,numVideo).sumSize=fileInfoPartition(numClass,numVideo).sumSize; %用中间变量nameRedundancyTempList来保存对应类别,视频,尺寸的独特的文件名和冗余文件名 nameRedundancyTempList={'0'};%保存对应类别,视频,尺寸的冗余的文件名 for numName=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize)%遍历每个类别对应视频下的对应尺寸的文件的多少 %初始化vainFlag,使其每次开始检测一个新的文件的时候,都是Ok的,后面发现如果是冗余数据,在置为0 vainFlag=1; %加入判断条件如果遍历到的文件名,已经保存在nameRedundancyTempList中,那么就不需要进行后续的检查了。直接下一个文件 sumRedundancy=length(nameRedundancyTempList); for i=1:sumRedundancy %如果在nameRedundancyTempList中发现了当前处理的文件 if strcmp(fileInfoPartition(numClass,numVideo).nameList{numSize,numName},nameRedundancyTempList{i}) vainFlag=0; break;%那么就置vainFlag为0,跳出这个循环,也就不用在进行下面的这个文件的所有操作了。 end end %如果在冗余列表中发现已有了这个文件,那么这个文件属于vain,就不用进行下面的计算判断了 if vainFlag %从头到尾,遍历整个文件名列表,作为要比较的原始数据 nameSource=[pathTemp,'\',num2str(numClass-1),'\',fileInfoPartition(numClass,numVideo).nameList{numSize,numName}]; picSource=im2double(imread(nameSource)); %为numName可能的最后一个文件名,没有东西可以比较的情况,增加一个特定的判断 %而且必须增加一个这样的判断,因为后面和原始图像相比较的,是它的后面一个图像 %那么如果numName是文件名最后一个序列的时候,不加if先排除,for会出错 if numName~=fileInfoPartition(numClass,numVideo).picSizeCount(numSize) %一开始也没有发现这个隐藏着的bug,不过好在后来发现了。bug藏的深呀,主要是自己编程经验太少了。这程序设计的逻辑有问题 %程序总体设计是,遍历对应尺寸的对应图片,用遍历图片后面的图片和它相比较。如果和它相似,那么说明这是冗余,就把这个图片 %放到冗余数据保存的列表nameRedundancyTempList中,然后基准按照遍历不断往后,如果发现当前的基准已经在列表nameRedundancyTempList %那么直接跳过,不执行后面的检验程序,因为已经被判定为冗余的数据,在比较其它的数据是否为冗余这不合理。不符合检验数据的逻辑 %但这程序如果没有后面的vainFlag1 %将存在一个问题,基准图片按照遍历在不断后移,后面比较的数据为当前基准后面到的所有数据,如果因为前面的基准图片已经被判断为 %冗余的数据,后面的基准要不要和这个数据进行比较再次判断它是不是冗余数据 %这肯定是不能再次判断的,因为有可能再次是冗余,那么就会再次添加到冗余列表中,造成冗余列表中有重复数据 %而非冗余列表虽然是通过和冗余列表中比较数据得到的这对应的文件名列表中,其实并不会造成错误,但是由于 %统计对应文件名列表的数据长度的字段picSizePartitionCount中的长度,是根据各个冗余列表文件名的长度和原始的 %结构体fileInfoPartition相减得到的,这就会出问题。导致把正确的数据划分到冗余数据中。 %所以这个bug是必须改正的。属于程序设计逻辑上存在问题 %而这个bug的隐蔽性在于,即使一开始这样两重重复遍历,由于一开始被判定为非冗余的数据和被判定为冗余的数据之间其实有差别的 %一般来说这个差别大于阈值,所以后面的数据并不会影响程序的运行,但是存在一种非常特殊的情况 %假定一开始的基准数据为a,先被判定为非冗余的数据为b,后面被判定为冗余的数据c。这数据还必须要存在这种顺序的排列(a、b、c) %虽然a和b差距较大。但是c处于a和b中的一种中间状态,与a和b都相似。所以a和b判定的时候,都会把c加到冗余列表中 %等于这个bug暴露要满足两个条件,a、b、c按顺序排列,c为a和b的一种中间状态 %主要还是程序设计的逻辑不严密,所以现在加入标识符vainFlag1,之前被判定为冗余的数据,就不和被判断为非冗余的数据再次比较了。 %被判断为非冗余的数据之和被判定为非冗余的数据相比较。逻辑严密并且节省了运算量 for numNameCompare=(numName+1):fileInfoPartition(numClass,numVideo).picSizeCount(numSize) %这其实就类似于之前行的vainFlag=1;及其类似 %初始化vainFlag1,使其每次开始一个新的对比文件的时候,都是1的,后面发现这个比较文件如果是冗余数据,再置为0 vainFlag1=1; %加入判断条件如果遍历到的文件名,已经保存在nameRedundancyTempList中,那么就不需要进行后续的检查了。直接下一个文件 sumRedundancy=length(nameRedundancyTempList); for i=1:sumRedundancy %如果在nameRedundancyTempList中发现了当前处理的文件 if strcmp(fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare},nameRedundancyTempList{i}) vainFlag1=0; break;%那么就置vainFlag为0,跳出这个循环,也就不用在进行下面的这个文件的所有操作了。 end end if vainFlag1 nameCompare=[pathTemp,'\',num2str(numClass-1),'\',fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare}]; picCompare=im2double(imread(nameCompare)); picResult=picSource-picCompare; %做出判断,如果差值里面有一个分量的范数大于0.5,那么就算是和原始图像有差距的图像 %if norm(picResult)>=differentCriterion %由于这里是灰度图像,所以只要测试一个维度就可以了 %Ave1,差值图像的二范数除以图像的尺寸,阈值0.005 %if norm(picResult)/numel(picResult)>=differentCriterion%这里的norm跟我想的操作是不一样的,要按照Ave2的方式写个程序 %Ave2,差值图像的平方和除以图像的尺寸再开根号,阈值0.05 if sqrt(sum(sum(picResult.^2))/numel(picResult))>=differentCriterion %那么就算是和原始图像有差距的图像,先不进行处理 else%如果范数不大于0.5,那么算是相似的图像,这个就可以保存在fileInfoResult的nameList中对应的偶数行中 nameRedundancyTempList=[nameRedundancyTempList;fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare}]; end end end end end end %在这步,基本就是属于在某个类别、视频、尺寸下,所有的冗余的尺寸尺寸信息都保存在了nameRedundancyTempList,所以用下面的语句把内容,放到偶数nameList中去。 nameRedundancyTempList=nameRedundancyTempList(2:end); sumRedundancy=length(nameRedundancyTempList); if 0==sumRedundancy %一开始没想到加这个if。主要是之前的方法忽略了一种极为特殊的情况,那就是如果在某类、某个视频,在某种尺寸下只有两个图片 %而且这两个图片是相异的(这种情况也有,也是后来发现程序运行bug,我才想到的) %毕竟图片挑选的时候也是尽量挑选不一样的,视频太短的话,可能会出现这种情况 %这种特殊的情况下,nameRedundancyTempList里面没有数据,sumRedundancy=0 %则后面往奇数行的namelist中添加文件名的操作没办法实现。所以这个if后面,就是往结构体fileInfoResult %的奇数行添加fileInfoPartition的整个文件名列表 for i=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize) fileInfoResult(numClass,numVideo).nameList(2*numSize-1,i)=fileInfoPartition(numClass,numVideo).nameList(numSize,i); end %对应的偶数行的nameList就是为空了 fileInfoResult(numClass,numVideo).nameList(2*numSize,1)={[]};%要注意这里赋空值的操作,一开始直接是[]赋值过去是不可以的 %补上这种特殊情况的picSizePartitionCount fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1,1)=fileInfoPartition(numClass,numVideo).picSizeCount(numSize,1); fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize,1)=0; else for i=1:sumRedundancy fileInfoResult(numClass,numVideo).nameList(2*numSize,i)=nameRedundancyTempList(i); end fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize,1)=sumRedundancy;%反正都算了sumRedundancy,顺带把计数字段填上 fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1,1)= ... fileInfoPartition(numClass,numVideo).picSizeCount(numSize)-sumRedundancy;%把计数字段不冗余的文件名补齐 %顺带把不冗余的文件名补齐 numName=1;%这里重新定义一个numName,和上面的(244行)遍历每个类别对应视频下的对应尺寸的文件的多少重复使用变量,但是互不干扰 for i=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize) for j=1:sumRedundancy if strcmp(fileInfoPartition(numClass,numVideo).nameList(numSize,i),fileInfoResult(numClass,numVideo).nameList(2*numSize,j)) %即为找到了这个文件名是冗余文件,那就没必要进行后面的判断 break; elseif j==sumRedundancy %如果在j等于sumRedundancy的时候,还没有找到同名文件,说明这个是独特的文件,那么添加到奇数的nameList中 fileInfoResult(numClass,numVideo).nameList(2*numSize-1,numName)=fileInfoPartition(numClass,numVideo).nameList(numSize,i); numName=numName+1; end end end end end end end %把结构体fileInfoPartition按阈值为分割在结构体fileInfoResult,耗时 disp(' '); disp(['把结构体fileInfoPartition按阈值',num2str(differentCriterion),'为分割在结构体fileInfoResult']); disp(['共耗时:',num2str(toc)]); %终于把需要的信息都按照需求整到了结构体fileInfoResult中 %在路径pathDestination根据标识符simplifyFlag和redundanceFlag %确定是否新建文件夹simplify和redundance,并在下面创建子文件夹0、1...9 %保存简化和冗余的数据 %要处理的数据的源地址,里面有子文件夹0、1、2...9 % pathSource='C:\Users\Dy\Desktop\sy1\val2'; %保存去冗余后数据的路径 %pathDestination='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr'; %是否生成无冗余数据的标志符号,为0,不生成,非0生成 %simplifyFlag=1; %是否生成冗余数据的标志符号,为0,不生成,非0生成 %redundanceFlag=1; %由于创建了两个标志符,所以最简单的编程方法就是一个标志一个标志编程 %开始拷贝去冗余的数据 tic; if simplifyFlag pathSimplify=[pathDestination,'\simplify']; mkdir(pathSimplify); %[sumClasses,maxFile]=size(fileInfoRaw); %sumVideo=length(videoList);%统计得到video的总数量 for numClass=1:sumClasses%对应的类别 mkdir([pathSimplify,'\',num2str(numClass-1),'\']); for numVideo=1:sumVideo%对应的视频序号 for numSize=1:fileInfoResult(numClass,numVideo).sumSize%对应的尺寸 for numName=1:fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1) copyfile([pathSource,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize-1,numName}], ... [pathSimplify,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize-1,numName}]); end end end end end disp(' '); disp(['拷贝简化后的数据共花费时间:',num2str(toc)]); %开始拷贝去冗余的数据 tic; if redundanceFlag pathredundance=[pathDestination,'\redundance']; mkdir(pathredundance); %[sumClasses,maxFile]=size(fileInfoRaw); %sumVideo=length(videoList);%统计得到video的总数量 for numClass=1:sumClasses%对应的类别 mkdir([pathredundance,'\',num2str(numClass-1),'\']); for numVideo=1:sumVideo%对应的视频序号 for numSize=1:fileInfoResult(numClass,numVideo).sumSize%对应的尺寸 for numName=1:fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize) copyfile([pathSource,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize,numName}], ... [pathredundance,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize,numName}]); end end end end end disp(' '); disp(['拷贝冗余的数据共花费时间:',num2str(toc)]); disp('程序执行完毕');
之前按照彩色图像处理数据冗余,发现这固定的阈值对于颜色比较单调的彩色图片数据是不利的。本想对于颜色比较单调的图像和颜色比较丰富的彩色图像,采用不同的阈值进行处理。但又感觉这不符合科学的精神。所以比较纠结,后来听师兄一说,先把彩色图像转为灰度图像,比较灰度图像,然后调对应的彩色图像作为训练集和测试集。感觉这样比较靠谱。对于颜色比较单调的图像和颜色比较丰富的彩色图像采用同一个阈值,这比较符合科学的精神。
1 clear;close all;clc; 2 %% 3 %由于程序运行的时间太长了,保存第一次运行的输出 4 % 程序开始执行 5 % 读取图片文件信息,并按类、视频序号、文件尺寸, 6 % 存到结构体fileInfoPartition中,耗时:185.7336 7 % 8 % 把结构体fileInfoPartition按阈值0.5为分割在结构体fileInfoResult 9 % 共耗时:3017.0879 10 % 11 % 拷贝简化后的数据共花费时间:54.1738 12 % 13 % 拷贝冗余的数据共花费时间:230.4289 14 %% 15 %程序如何操作: 16 %变量pathSource为要处理的图片数据,所在的文件夹,就数字时间码识别而言。就是各个子分类0、1、2上一级文件夹 17 %变量pathTemp为保存灰度中变变量图像的文件夹 18 %变量pathDestination改为处理好数据保存的文件夹 19 %destinationFlag和redundanceFlag分别控制是否保存原始的数据和冗余数据 20 %% 21 %下一步改进: 22 %统计简化数据和冗余数据分别都有多少 23 %现在求的阈值是整体的二范数,没有考虑到图像尺寸的影响。下一步看二范数除以尺寸后再加阈值判断 24 %% 25 %程序实现的功能 26 %1、先把彩色图像转换为灰度图像 27 %2、在灰度图像中,根据指定的路径、视频序号和差距系数,挑选出对应相同视频号的相同位置数字的冗余的 28 %3、把先前挑选出的灰度数据对应的彩色图像精简的保存在文件夹pathdestination、冗余数据保存在文件夹pathredundance 29 %% 30 %程序中用到的新功能:之前一直没用过结构体,现在用了结构体数组。 31 %参考程序decreaseRedundantColor 32 %1) 33 %2) 34 %3) 35 %4) 36 %5) 37 %% 38 %变量命名规则: 39 %总路径下一层的文件夹记为dir(directory) 40 %最后一层就是各个文件记为file 41 %% 42 %程序编程思路: 43 %如果只考虑不过数据之间的差异性,而作差二范数,后阈值处理。这样存在颜色比较丰富的彩色图像,会保留更多。 44 %而颜色相对单调的图像,保留的数据更少。这不公平,而如果对于这两种图像采用不同的阈值,这又违反了科学的精神 45 %所以考虑到先都转化为灰度图像,然后用相同的阈值进行比较。这样来去除冗余数据,这样和之后肯定会进行的PCA处理,想呼应。 46 %这才是我目前认为最科学的数据处理方法 47 tic; 48 disp('程序开始执行'); 49 %%%%%%%%%%%%需要更改的参数%%%%%%%%%%%%%%%%%%%% 50 %要处理的数据的源地址,里面有子文件夹0、1、2...9 51 52 pathSource='C:\Users\Dy\Desktop\彩色视频真实数据\sjz'; 53 54 %保存中间数据灰度图像的文件夹 55 56 pathTemp='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr\tempGray'; 57 58 %保存去冗余后数据的路径 59 60 pathDestination='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr'; 61 62 %是否生成无冗余数据的标志符号,为0,不生成,非0生成 63 64 simplifyFlag=1; 65 66 %是否生成冗余数据的标志符号,为0,不生成,非0生成 67 68 redundanceFlag=1; 69 70 %判断数据,是否冗余的阈值,初步选为0.5 71 72 differentCriterion=0.5; 73 74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 75 76 %先读取pathSource文件夹下存在的子文件,保存子文件夹信息。方便后面处理。 77 dirList=dir(pathSource);%读取文件夹列表,这种方式读取会保留原文件.(在结构体中第一个)和上一层目录..(在结构体第二个) 78 countDir=length(dirList);%文件夹个数 79 tic; 80 %先把彩色图像转换为灰度图像,放在文件夹pathTemp中,方便后面的比较图像 81 for numDir=3:countDir%先读取数据文件夹pathSource下的子文件夹 82 if(length(dirList(numDir).name)>=2)%根据这个过滤掉在此文件夹可能存在的各种txt文件 83 continue; 84 end 85 %为中间变量灰度图想创建保存数据的子文件 86 pathCreDir=[pathTemp,'\',dirList(numDir).name,'\']; 87 mkdir(pathCreDir); 88 89 fileList=dir([pathSource,'\',dirList(numDir).name]); 90 countFile=length(fileList); 91 disp(['正在转换子文件夹',dirList(numDir).name,'中的图像']); 92 for numFile=3:countFile%依次读取所有的文件名 93 tempName=[pathSource,'\',dirList(numDir).name,'\',fileList(numFile).name];%依次得到具体图片文件的完整路径 94 temp=imread(tempName);%读入图片 95 graytemp=rgb2gray(temp);%彩色图像转化为灰度图像 96 97 %保存在和源文件一样的对应文件夹内,按同样的文件名、文件类型保存 98 imwrite(graytemp,[pathCreDir,fileList(numFile).name]); 99 end 100 disp(['共转换了',num2str(countFile-2),'张图片']) 101 end 102 disp(['把彩色图像转换为灰度图像,并保存在中间变量文件夹',pathTemp]); 103 disp(['共耗时:',num2str(toc)]) 104 105 106 %% 107 %直接处理中间变量文件夹中的数据,然后按得到的结果从彩色图像源文件夹分割数据去冗余 108 %整体仿照文件decreaseRedundantColor.m编写 109 %提取出原始数据里面的有用数据保存到结构体中 110 %把文件的全部信息一次性全部先读取到一个结构体数组fileInfoRaw中来 111 % 结构体数字,第一维为类别(相对应子文件夹文件名加1),第二维为图片序号 112 % 结构体数组中有字段 113 % name:图片的名字 114 % videonum:图片来源于那个视频 115 % size:[图片的宽(竖直方向跨度),图片的长度(水平方向跨度)] 116 tic; 117 dirList=dir(pathTemp);%读取文件夹列表,这种方式读取会保留原文件.(在结构体中第一个)和上一层目录..(在结构体第二个) 118 countDir=length(dirList);%文件夹个数 119 for numDir=3:countDir%先读取数据文件夹pathSource下的子文件夹 120 if(length(dirList(numDir).name)>=2)%根据这个过滤掉在此文件夹可能存在的各种txt文件 121 continue; 122 end 123 fileList=dir([pathTemp,'\',dirList(numDir).name]); 124 countFile=length(fileList); 125 for numFile=3:countFile%依次读取所有的文件名 126 %去除图片所属的视频序号 127 tempName=fileList(numFile).name; 128 nameStart=strfind(tempName,'_'); 129 nameEnd=strfind(tempName,'-'); 130 tempVideoOrder=tempName(nameStart+1:nameEnd-1); 131 tempPic=imread([pathTemp,'\',dirList(numDir).name,'\',fileList(numFile).name]); 132 %tempSize=size(tempPic);%读取的当前图片的size 133 %要注意提取出来的子文件的名称再加1得到了结构体的数据信息,而numFile是从第3开始的,所以要减2 134 fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).name=tempName; 135 fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).videonum=str2double(tempVideoOrder); 136 fileInfoRaw(str2double(dirList(numDir).name)+1,numFile-2).size=size(tempPic); 137 end 138 end 139 140 %读取出所有的视频序号 141 %读取第一个子文件中的视频数据(一般而言每个视频肯定都会生成数据0,所以读取0文件夹可以选出所有的视频序号的) 142 [sumClasses,maxFile]=size(fileInfoRaw); 143 videoList(1)={0};%cell中第一项填充一个0方面后续的程序编写。 144 %原本想去除所有的视频序号,然后用unique提取出唯一信息。 145 %但由于视频序号并不是统一规格的长短,所以只能用比较麻烦的方法。 146 % for numFile=1:maxFile 147 % if ~isempty(fileInfoRaw(numFile).videonum) 148 % videoList=[videoList;fileInfoRaw(numFile).videonum]; 149 % end 150 % end 151 %读取第一个结构体,就是子文件夹0中的图片数量,挑选没有重复的数据 152 for numFile=1:maxFile 153 %注意这里的fileInfoRaw(1,numFile),就是指定了子文件夹0中的数据,不能忘记这个1 154 if ~isempty(fileInfoRaw(1,numFile).videonum) 155 countVideo=length(videoList); 156 for tempVideoNum=1:countVideo 157 if videoList{tempVideoNum} == fileInfoRaw(1,numFile).videonum 158 continue; 159 else 160 %一开始没加这行,伤不起呀。必须是比较完videoList中所有的 161 %视频序号都没有相同的视频,才开始往videoList中添加 162 if tempVideoNum == countVideo 163 %下面这种方式,对于cell的操作,每次videoList多生成一行 164 videoList=[videoList;fileInfoRaw(1,numFile).videonum]; 165 end 166 end 167 end 168 end 169 end 170 videoList=videoList(2:end);%删除第一项,得到了要处理的视频序号 171 sumVideo=length(videoList);%统计得到video的总数量 172 173 %由于要记录的信息太多,而又想不到能一步得到很多信息的方法。 174 %所以就把这些东西简单分为一小部分一小部分记录 175 %用二维结构体数组fileInfoSize保存图片的尺寸信息,第一维为类别,第二维为对应于videoList中相同位置的视频 176 %先用tempSize保存某一类,某一视频序号videoList{numVideo}下的所有的尺寸信息, 177 %然后再把这些信息保存到结构体fileInfoSize中 178 %结构体数组中有字段 179 %size:保存着对应于行(类别),列(视频videoList{numVideo})的所有尺寸 180 for numClass=1:sumClasses%对应的类别 181 for numVideo=1:sumVideo%对应的视频序号 182 tempSize={[0,0,0]};%必须是cell,才能方便每次统计在某个类别下面对应视频的size总数 183 %下面这个for,就是判断指定类别,指定视频序号的所有尺寸的累加 184 for i=1:maxFile 185 %因为结构体也是按最大尺寸,填充的,所以有一些是空的 186 %先判断,如果是空数据就不进行处理 187 if isempty(fileInfoRaw(numClass,i).videonum) 188 break; 189 %一次也就判断指定视频的尺寸,所以下面加入判断是对应的视频才处理 190 elseif videoList{numVideo}==fileInfoRaw(numClass,i).videonum 191 192 countTempSize=length(tempSize); 193 %选取到某一个文件信息,然后用tempSize中的所有尺寸信息和其比较,如果都不相同,在添加到tempSize中 194 for numTempSize=1:countTempSize 195 %先用setdiff判断数组tempSize{numTempSize}和fileInfoRaw(numClass,i).size 196 %是否相同,如果相同则返回空,正好用isempty判断 197 %下面一开始判断两个数组是否相等是只有语句isempty(setdiff(tempSize{numTempSize},fileInfoRaw(numClass,i).size)) 198 %而这个函数为setdiff(a,b)只是返回b中没有的,a的值,那么遇到a=[17 17 3] 199 %b=[17 15 3],则setdiff(a,b)返回空,所以用了下面这种加强的判断方法, 200 %[setdiff(a,b),setdiff(b,a)]注意两个数组直接连接用的是逗号 201 %这样就可以两个数组直接是不是相等,完全判断 202 if isempty([setdiff(tempSize{numTempSize},fileInfoRaw(numClass,i).size),setdiff(fileInfoRaw(numClass,i).size,tempSize{numTempSize})]) 203 %一开始这写为continue,这是错误的。因为上面的for是在整个tempSize里面 204 %找是否有相同的,有相同的就停止执行后面的else中的添加功能。 205 %如果改为continue了,反倒成了找tempSize中是否有和当前size中不同的数据 206 %如果有,就加进tempSize中。这相当蛋疼。哎,太菜了。 207 %不过也是之前没写过那么复杂的程序。。。。 208 break; 209 else 210 %又忘了加后面这个判断了,如果是所有的在tempSize中的尺寸都比较完之后 211 %还是没有发现和fileInfoRaw(numClass,i).size相同的数据,才往 212 %tempSize中添加新数据 213 if numTempSize == countTempSize 214 tempSize=[tempSize;fileInfoRaw(numClass,i).size]; 215 end 216 end 217 end 218 end 219 end 220 %上面这个for,就取出了对应类别,对应视频的所有不同的尺寸,由于有个初始的[0,0,0] 221 %所以去掉第一个初始值,从第二个开始 222 tempSize=tempSize(2:end); 223 fileInfoPartition(numClass,numVideo).picSize=tempSize; 224 end 225 end 226 227 %把每个类、每个视频中的所有的尺寸信息保存到了结构体fileInfoSize中, 228 %在结构体fileInfoSize再加入sumSize这个字段来统计,对应结构体下各种多少种size的图像 229 for numClass=1:sumClasses%对应的类别 230 for numVideo=1:sumVideo%对应的视频序号 231 fileInfoPartition(numClass,numVideo).sumSize=size(fileInfoPartition(numClass,numVideo).picSize,1); 232 end 233 end 234 235 %往结构体fileInfoPartition中添加字段nameList 236 %nameList中有sumSize行,分别对应于picSize中各行的尺寸 237 %由于早已经把要处理的信息都保存在结构体fileInforRaw,所以只要读取里面的信息就可以了 238 %[sumClasses,maxFile]=size(fileInfoRaw); 239 %sumVideo=length(videoList);%统计得到video的总数量 240 for numClass=1:sumClasses%对应的类别 241 for numVideo=1:sumVideo%对应的视频序号 242 for numSize=1:fileInfoPartition(numClass,numVideo).sumSize%遍历每个类别对应视频下的所有尺寸数据 243 tempName={'0'};%cell类型,方便统计最后的相同尺寸的文件的数量,可以存放不同类型的数据 244 for numFile=1:maxFile 245 %由于结构体,会规整整个结构体的尺寸,所以要首先判断,当前结构体数字下的内容是否为空 246 if isempty(fileInfoRaw(numClass,numFile).videonum) 247 %按顺序遍历整个结构体中的数据,如果发现空内容,所以当前分类的数据已经、 248 %遍历完,所以break,进入下一个类 249 break; 250 elseif videoList{numVideo}==fileInfoRaw(numClass,numFile).videonum 251 %上面先进行判断是不是属于这个视频的数据 252 %下面判断,是不是属于这个尺寸的数据 253 if isempty([setdiff(fileInfoPartition(numClass,numVideo).picSize{numSize},fileInfoRaw(numClass,numFile).size), ... 254 setdiff(fileInfoRaw(numClass,numFile).size,fileInfoPartition(numClass,numVideo).picSize{numSize})]) 255 tempName=[tempName;fileInfoRaw(numClass,numFile).name]; 256 end 257 end 258 end 259 %上面这个for为在某个类别,对应视频序号,按顺序的某个尺寸遍历完的所有文件名列表 260 tempName=tempName(2:end); 261 %由于打算把计算出来的文件名列表保存按行(对应于结构体中picSize中的尺寸信息) 262 %而这样文件名列表不同行(即不同尺寸)的文件数量是不相等的 263 %对于这种不同维度的数据,直接一行一行操作cell会出错,所以只能一个一个进行添加 264 sumName=length(tempName); 265 for i=1:sumName 266 fileInfoPartition(numClass,numVideo).nameList(numSize,i)=tempName(i); 267 end 268 %想到了反正都算出了了不同类别不同视频不同尺寸的文件数量 269 %那就把这个信息保存到结构体的字段picSizeCount中,每行都对应picSize中文件数量 270 fileInfoPartition(numClass,numVideo).picSizeCount(numSize,1)=sumName; 271 end 272 end 273 end 274 %读取文件信息,并按类、视频序号、文件名尺寸存到结构体fileInfoPartition中 275 disp('读取图片文件信息,并按类、视频序号、文件尺寸,'); 276 disp(['存到结构体fileInfoPartition中,耗时:',num2str(toc)]); 277 278 %% 279 %终于把有用的信息都提取到了结构体fileInfoPartition中,结构体总共有10行(10个类别),n列(n个视频) 280 %结构体有字段: 281 %picSize:对应类(结构体行)和视频(结构体列)的数据的尺寸 282 %sumSize:对应类(结构体行)和视频(结构体列)的数据的各种尺寸的总数 283 %nameList:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件名列表 284 %picSizeCount:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件总数 285 286 %计划把判断是否冗余,计算好后的数据保存到结构体fileInfoResult中 287 %picSize:对应类(结构体行)和视频(结构体列)的数据的尺寸 288 %sumSize:对应类(结构体行)和视频(结构体列)的数据的各种尺寸的总数 289 %nameList:对应类(结构体行)和视频(结构体列)和对应数据的尺寸(对应于字段picSize的行)的文件名列表 290 %和fileInfoPartition中数据相比是它的两倍的行数,相当于把fileInfoPartition中的每一行拆为两行,奇数行为冗余 291 %偶数行为对应的未冗余 292 %picSizePartitionCount:对应于namelist中各行的数据量 293 294 tic; 295 %先把数据在新建的结构体中完成分割,然后再根据destinationFlag和redundanceFlag确定是否要写入分割的数据 296 %先整体扫描结构体中fileInfoPartition,计算出所有的是否冗余的信息,然后存到fileInfoResult中 297 % pathSource='C:\Users\Dy\Desktop\彩色视频真实数据\val2'; 298 %[sumClasses,maxFile]=size(fileInfoRaw); 299 %sumVideo=length(videoList);%统计得到video的总数量 300 %vainFlag:发现要添加一个vainFlag的标记来,取消掉某一个文件名的重复比较 301 %主要是考虑到每到一个文件名,都要计算后面所有的文件是否重复,这个计算量有点大。 302 %而且如果不添加这个flag,会导致比如重复图片中的最后一个图片会被添加到无冗余数据的列表中 303 for numClass=1:sumClasses%对应的类别 304 for numVideo=1:sumVideo%对应的视频序号 305 % if numVideo==3 306 % temp=1; 307 % end 308 for numSize=1:fileInfoPartition(numClass,numVideo).sumSize%遍历每个类别对应视频下的所有尺寸数据 309 %把字段picSize和sumSize也补上 310 fileInfoResult(numClass,numVideo).picSize=fileInfoPartition(numClass,numVideo).picSize; 311 fileInfoResult(numClass,numVideo).sumSize=fileInfoPartition(numClass,numVideo).sumSize; 312 %用中间变量nameRedundancyTempList来保存对应类别,视频,尺寸的独特的文件名和冗余文件名 313 nameRedundancyTempList={'0'};%保存对应类别,视频,尺寸的冗余的文件名 314 for numName=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize)%遍历每个类别对应视频下的对应尺寸的文件的多少 315 %初始化vainFlag,使其每次开始检测一个新的文件的时候,都是Ok的,后面发现如果是冗余数据,在置为0 316 vainFlag=1; 317 %加入判断条件如果遍历到的文件名,已经保存在nameRedundancyTempList中,那么就不需要进行后续的检查了。直接下一个文件 318 sumRedundancy=length(nameRedundancyTempList); 319 for i=1:sumRedundancy 320 %如果在nameRedundancyTempList中发现了当前处理的文件 321 if strcmp(fileInfoPartition(numClass,numVideo).nameList{numSize,numName},nameRedundancyTempList{i}) 322 vainFlag=0; 323 break;%那么就置vainFlag为0,跳出这个循环,也就不用在进行下面的这个文件的所有操作了。 324 end 325 end 326 %如果在冗余列表中发现已有了这个文件,那么这个文件属于vain,就不用进行下面的计算判断了 327 if vainFlag 328 %从头到尾,遍历整个文件名列表,作为要比较的原始数据 329 nameSource=[pathTemp,'\',num2str(numClass-1),'\',fileInfoPartition(numClass,numVideo).nameList{numSize,numName}]; 330 picSource=im2double(imread(nameSource)); 331 %为numName可能的最后一个文件名,没有东西可以比较的情况,增加一个特定的判断 332 %而且必须增加一个这样的判断,因为后面和原始图像相比较的,是它的后面一个图像 333 %那么如果numName是文件名最后一个序列的时候,不加if先排除,for会出错 334 if numName~=fileInfoPartition(numClass,numVideo).picSizeCount(numSize) 335 %一开始也没有发现这个隐藏着的bug,不过好在后来发现了。bug藏的深呀,主要是自己编程经验太少了。这程序设计的逻辑有问题 336 %程序总体设计是,遍历对应尺寸的对应图片,用遍历图片后面的图片和它相比较。如果和它相似,那么说明这是冗余,就把这个图片 337 %放到冗余数据保存的列表nameRedundancyTempList中,然后基准按照遍历不断往后,如果发现当前的基准已经在列表nameRedundancyTempList 338 %那么直接跳过,不执行后面的检验程序,因为已经被判定为冗余的数据,在比较其它的数据是否为冗余这不合理。不符合检验数据的逻辑 339 %但这程序如果没有后面的vainFlag1 340 %将存在一个问题,基准图片按照遍历在不断后移,后面比较的数据为当前基准后面到的所有数据,如果因为前面的基准图片已经被判断为 341 %冗余的数据,后面的基准要不要和这个数据进行比较再次判断它是不是冗余数据 342 %这肯定是不能再次判断的,因为有可能再次是冗余,那么就会再次添加到冗余列表中,造成冗余列表中有重复数据 343 %而非冗余列表虽然是通过和冗余列表中比较数据得到的这对应的文件名列表中,其实并不会造成错误,但是由于 344 %统计对应文件名列表的数据长度的字段picSizePartitionCount中的长度,是根据各个冗余列表文件名的长度和原始的 345 %结构体fileInfoPartition相减得到的,这就会出问题。导致把正确的数据划分到冗余数据中。 346 %所以这个bug是必须改正的。属于程序设计逻辑上存在问题 347 %而这个bug的隐蔽性在于,即使一开始这样两重重复遍历,由于一开始被判定为非冗余的数据和被判定为冗余的数据之间其实有差别的 348 %一般来说这个差别大于阈值,所以后面的数据并不会影响程序的运行,但是存在一种非常特殊的情况 349 %假定一开始的基准数据为a,先被判定为非冗余的数据为b,后面被判定为冗余的数据c。这数据还必须要存在这种顺序的排列(a、b、c) 350 %虽然a和b差距较大。但是c处于a和b中的一种中间状态,与a和b都相似。所以a和b判定的时候,都会把c加到冗余列表中 351 %等于这个bug暴露要满足两个条件,a、b、c按顺序排列,c为a和b的一种中间状态 352 %主要还是程序设计的逻辑不严密,所以现在加入标识符vainFlag1,之前被判定为冗余的数据,就不和被判断为非冗余的数据再次比较了。 353 %被判断为非冗余的数据之和被判定为非冗余的数据相比较。逻辑严密并且节省了运算量 354 for numNameCompare=(numName+1):fileInfoPartition(numClass,numVideo).picSizeCount(numSize) 355 %这其实就类似于之前行的vainFlag=1;及其类似 356 %初始化vainFlag1,使其每次开始一个新的对比文件的时候,都是1的,后面发现这个比较文件如果是冗余数据,再置为0 357 vainFlag1=1; 358 %加入判断条件如果遍历到的文件名,已经保存在nameRedundancyTempList中,那么就不需要进行后续的检查了。直接下一个文件 359 sumRedundancy=length(nameRedundancyTempList); 360 for i=1:sumRedundancy 361 %如果在nameRedundancyTempList中发现了当前处理的文件 362 if strcmp(fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare},nameRedundancyTempList{i}) 363 vainFlag1=0; 364 break;%那么就置vainFlag为0,跳出这个循环,也就不用在进行下面的这个文件的所有操作了。 365 end 366 end 367 if vainFlag1 368 nameCompare=[pathTemp,'\',num2str(numClass-1),'\',fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare}]; 369 picCompare=im2double(imread(nameCompare)); 370 picResult=picSource-picCompare; 371 %做出判断,如果差值里面有一个分量的范数大于0.5,那么就算是和原始图像有差距的图像 372 if norm(picResult)>=differentCriterion %由于这里是灰度图像,所以只要测试一个维度就可以了 373 %那么就算是和原始图像有差距的图像,先不进行处理 374 375 else%如果范数不大于0.5,那么算是相似的图像,这个就可以保存在fileInfoResult的nameList中对应的偶数行中 376 nameRedundancyTempList=[nameRedundancyTempList;fileInfoPartition(numClass,numVideo).nameList{numSize,numNameCompare}]; 377 end 378 end 379 end 380 end 381 end 382 end 383 %在这步,基本就是属于在某个类别、视频、尺寸下,所有的冗余的尺寸尺寸信息都保存在了nameRedundancyTempList,所以用下面的语句把内容,放到偶数nameList中去。 384 nameRedundancyTempList=nameRedundancyTempList(2:end); 385 sumRedundancy=length(nameRedundancyTempList); 386 if 0==sumRedundancy 387 %一开始没想到加这个if。主要是之前的方法忽略了一种极为特殊的情况,那就是如果在某类、某个视频,在某种尺寸下只有两个图片 388 %而且这两个图片是相异的(这种情况也有,也是后来发现程序运行bug,我才想到的) 389 %毕竟图片挑选的时候也是尽量挑选不一样的,视频太短的话,可能会出现这种情况 390 %这种特殊的情况下,nameRedundancyTempList里面没有数据,sumRedundancy=0 391 %则后面往奇数行的namelist中添加文件名的操作没办法实现。所以这个if后面,就是往结构体fileInfoResult 392 %的奇数行添加fileInfoPartition的整个文件名列表 393 for i=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize) 394 fileInfoResult(numClass,numVideo).nameList(2*numSize-1,i)=fileInfoPartition(numClass,numVideo).nameList(numSize,i); 395 end 396 %对应的偶数行的nameList就是为空了 397 fileInfoResult(numClass,numVideo).nameList(2*numSize,1)={[]};%要注意这里赋空值的操作,一开始直接是[]赋值过去是不可以的 398 %补上这种特殊情况的picSizePartitionCount 399 fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1,1)=fileInfoPartition(numClass,numVideo).picSizeCount(numSize,1); 400 fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize,1)=0; 401 else 402 for i=1:sumRedundancy 403 fileInfoResult(numClass,numVideo).nameList(2*numSize,i)=nameRedundancyTempList(i); 404 end 405 fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize,1)=sumRedundancy;%反正都算了sumRedundancy,顺带把计数字段填上 406 fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1,1)= ... 407 fileInfoPartition(numClass,numVideo).picSizeCount(numSize)-sumRedundancy;%把计数字段不冗余的文件名补齐 408 %顺带把不冗余的文件名补齐 409 numName=1;%这里重新定义一个numName,和上面的(244行)遍历每个类别对应视频下的对应尺寸的文件的多少重复使用变量,但是互不干扰 410 for i=1:fileInfoPartition(numClass,numVideo).picSizeCount(numSize) 411 for j=1:sumRedundancy 412 if strcmp(fileInfoPartition(numClass,numVideo).nameList(numSize,i),fileInfoResult(numClass,numVideo).nameList(2*numSize,j)) 413 %即为找到了这个文件名是冗余文件,那就没必要进行后面的判断 414 break; 415 elseif j==sumRedundancy 416 %如果在j等于sumRedundancy的时候,还没有找到同名文件,说明这个是独特的文件,那么添加到奇数的nameList中 417 fileInfoResult(numClass,numVideo).nameList(2*numSize-1,numName)=fileInfoPartition(numClass,numVideo).nameList(numSize,i); 418 numName=numName+1; 419 end 420 end 421 end 422 end 423 end 424 end 425 end 426 %把结构体fileInfoPartition按阈值为分割在结构体fileInfoResult,耗时 427 disp(' '); 428 disp(['把结构体fileInfoPartition按阈值',num2str(differentCriterion),'为分割在结构体fileInfoResult']); 429 disp(['共耗时:',num2str(toc)]); 430 431 %终于把需要的信息都按照需求整到了结构体fileInfoResult中 432 433 %在路径pathDestination根据标识符simplifyFlag和redundanceFlag 434 %确定是否新建文件夹simplify和redundance,并在下面创建子文件夹0、1...9 435 %保存简化和冗余的数据 436 %要处理的数据的源地址,里面有子文件夹0、1、2...9 437 % pathSource='C:\Users\Dy\Desktop\sy1\val2'; 438 %保存去冗余后数据的路径 439 %pathDestination='C:\Users\Dy\Desktop\彩色视频真实数据\sjdr'; 440 %是否生成无冗余数据的标志符号,为0,不生成,非0生成 441 %simplifyFlag=1; 442 %是否生成冗余数据的标志符号,为0,不生成,非0生成 443 %redundanceFlag=1; 444 %由于创建了两个标志符,所以最简单的编程方法就是一个标志一个标志编程 445 %开始拷贝去冗余的数据 446 tic; 447 if simplifyFlag 448 pathSimplify=[pathDestination,'\simplify']; 449 mkdir(pathSimplify); 450 %[sumClasses,maxFile]=size(fileInfoRaw); 451 %sumVideo=length(videoList);%统计得到video的总数量 452 for numClass=1:sumClasses%对应的类别 453 mkdir([pathSimplify,'\',num2str(numClass-1),'\']); 454 for numVideo=1:sumVideo%对应的视频序号 455 for numSize=1:fileInfoResult(numClass,numVideo).sumSize%对应的尺寸 456 for numName=1:fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize-1) 457 copyfile([pathSource,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize-1,numName}], ... 458 [pathSimplify,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize-1,numName}]); 459 end 460 end 461 end 462 end 463 end 464 disp(' '); 465 disp(['拷贝简化后的数据共花费时间:',num2str(toc)]); 466 467 %开始拷贝去冗余的数据 468 tic; 469 if redundanceFlag 470 pathredundance=[pathDestination,'\redundance']; 471 mkdir(pathredundance); 472 %[sumClasses,maxFile]=size(fileInfoRaw); 473 %sumVideo=length(videoList);%统计得到video的总数量 474 for numClass=1:sumClasses%对应的类别 475 mkdir([pathredundance,'\',num2str(numClass-1),'\']); 476 for numVideo=1:sumVideo%对应的视频序号 477 for numSize=1:fileInfoResult(numClass,numVideo).sumSize%对应的尺寸 478 for numName=1:fileInfoResult(numClass,numVideo).picSizePartitionCount(2*numSize) 479 copyfile([pathSource,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize,numName}], ... 480 [pathredundance,'\',num2str(numClass-1),'\',fileInfoResult(numClass,numVideo).nameList{2*numSize,numName}]); 481 end 482 end 483 end 484 end 485 end 486 disp(' '); 487 disp(['拷贝冗余的数据共花费时间:',num2str(toc)]);