飞思卡尔智能车图像处理
2018-03-09 13:15:27 nanhaiyuhai 阅读数 4132

今天是2018年3月9日,在经过一段时间熟悉赛道和小车特性之后,我正式开始飞思卡尔智能车的图像处理学习,并负责我们组 图像算法的编写.

首先是图像的二值化处理

 二值化算法的思路是:设定一个阈值valve,对于视频信号矩阵中的每一行,从左至右比较各像素值和阈值的大小,若像素值大于或等于阈值,则判定该像素对应的是白色赛道;反之,则判定对应的是黑色的目标引导线。记下第一次和最后一次出现像素值小于阈值时的像素点的列号,算出两者的平均值,以此作为该行上目标引导线的位置。

二值化简单理解就是以一个值为基准,大于(等于)这个值的数全部变为是1(或者0),小于等于这个数的就全部将他们变为0(或1)。

    举个例子吧:1~1010个数,现在要将它们二值化处理。那怎么做呢?我可以以5做为基准值,用1~10的数每个与5做比较,将大于等于5的数全部置1,将小于5的数全部置0。这就实现了1~10这些数据的二值化。这个5就是我们所说的阈值。当然阈值5是我自己设定的,我也可与将483等等作为阈值,也可以将大于阈值的数全置为0,小于等于阈值的数全部置为1,都的可以的,其中的01也是可以其他值,如0255,随便两个值都可,根据自己的需求便可。

    摄像头的二值化的基本代码为(看起来是异常的简单):

 

Void image_binaryzation()

{

for(int i=0;i

{

    for(int j=0;j

    {

if(Image[i][j] >= Threshold)

       Image_new[i][j]=1;

else

    Image_new[i][j]=0;

    }

}

}

    其中 Row是对应采集到的行数,Col是列数,Image[i][j]是摄像头采集未二值化的数据存放的数组,Img[i][j]是新建的存放二值化后的数组;


2019-01-16 20:51:11 m0_37454852 阅读数 694

声明:本文曾发表至智能车制作论坛,仍为本人所编著,非抄袭!各位大佬若需转载请注明出处!感谢!(解读部分北科图像处理内容

北科技术报告部分内容:

(1) 直接逐行扫描原始图像,根据设定的阈值提取黑白跳变点;   
(2) 赛道宽度有一个范围,在确定的赛道宽度范围内提取有效赛道边沿,这
样可以滤除不在宽度范围内的干扰;   
(3) 利用赛道的连续性,根据上一行白块的位置和边沿的位置来确定本行的 边沿点;   
(4)求边沿点时,因为近处的图像稳定,远处图像不稳定,所以采用由近及 远的办法;
5) 进出十字的时候,通过校正计算出边沿角度可较好的滤除十字并补线;

点到为止

这里点一下:八连通寻边。  
  十字判断那部分:根据原始图像特性,找出可能出现的十字折角那个点(我用了极值点+其他判断条件),再计算折点两侧附近的斜率值,根据两个斜率值利用反三角函数计算角度,进一步判断是否为十字,之后补线看你本事吧,点到为止。(论坛里经常有小白问斜入十字怎么办,只有距离十字特别近才能判断十字怎么办,基本迎刃而解)

嗯就说这么多吧,点到为止啊滑稽。

噢对了,平移赛道半宽不是拿数组存储原始图像在直道上的每一行上的半宽,丢线了就加上去那么简单的。(见过很多人那么做,虽然也能用)
  想问北科怎么实现的,先把矫正反矫正写出来再说吧。(这里有一个我以前写的一个渣渣博客,不太愿意更新了,大家可以小做参考吧……恩智浦杯(飞思卡尔)全国大学生智能车竞赛摄像头简单的图像失真矫正技术原理与实现(透视变换)

点到为止,点到为止。

加个彩蛋:
  有大佬想过不用反矫正,直接利用矫正后的点计算加权偏差进行反馈控制的嘛?

2016-11-08 23:05:38 BaiYH1994 阅读数 26933

    由于是第一次写技术博客,先做一下自我介绍。本人本科专业是光电信息科学与工程(工),就读于长春理工大学光电工程学院,研究生为华中科技大学光学工程专业。本科期间参加参加过各类比赛,其中印象最深的还是智能车竞赛。参加了十届和十一届的智能车竞赛,当然结果是都没有出校赛这让我很尴尬。做了两届的摄像头,第一年跑的速度是1.8m/s第二年跑到了3m/s以上。虽然最后有一些可惜但是我希望把我自己的一些感想和遇到的问题给大家介绍一下,分享一下我的经验,希望能够对学弟学妹有一些帮助。

  步入主题,智能车竞赛摄像头组主要包括几个部分,我就以采集图像;赛道模式识别;控制算法;PID算法;机械结构调整等几个方面为大家介绍我的整体思路。


  首先我先说一下我第二年用的是B车具体车型自己可以百度一下吧,在这里我简单介绍一下,它用的是一个大电机,速度个人认为是其他车无法比拟的,然后舵机用的是SD-5舵机,是一个数字舵机它的响应频率很快,可以满足我用很高的频率去控制转角,这样也对于控制方面提供了方便。

  接下来谈谈如何调整机械部分,首先摄像头的位置,个人把摄像头放在了整个车的重心位置,也就是整个车的中间。舵机采用卧式结构,推荐采用卧式或立式,舵机与摄像头之间放置的电池,为什么将电池放在这是因为为了让整个车的重心靠近中间,摄像头我直接开到了电路板上,将电路板固定在底盘上,整个主控上面包含了所有的模块,节省了空间降低了重心。整车拼起来后最高的位置是舵机和轮子,个人喷了黑色喷漆感觉很帅(这个是看个人了)。前轮调整的时候很多人很迷茫在这我给大家说一下,前轮内八,让最小的转弯半径越大越好,可以得到很好地转弯效果,又因为我的电池是靠近舵机的所以增加了转弯时候的侧滑力量,内八的程度是多少呢就是当打到最大角度的时候轮子稍微给点离心力就可以所有的面都着地,这样就是最好的状态,还有就是舵机的拉杆,要V字型,为什么呢,就是为了当摆角最大的时候舵机给的推力是最大的,当摆角小的时候舵机反应不是特别灵敏(吉林大学车辆工程的一位车友告诉的方法),这样调整完前轮后就是后轮的调整,调整到什么状态呢,当电机给最大占空比的时候只要按住车瞬间电机就能停住,这样就可以让以后编码器测出来的数据不会有空转的情况(自己慢慢测试就好没有什么很好地方法),安装编码器的时候编码器齿轮与后车轮的齿轮啮合要怎么检测呢,就是当你转动编码器齿轮时候看不出空回,如果有空回就要继续调整直道看不出空回为止。到此为止只有一个事情要解决了,那就是B车底盘的问题,这个东西的话大家很多人是不知道的,就是买车模的时候它会给两个小块通常是黑色的(我当时以为这个东西是鸡肋,后来才知道我太天真了。),它是用来垫前轮的底盘的(具体名词不知道想了解可以百度),然后后轮如果拆下来可以看见轮轴与底盘连接那个位置有个类似椭圆的一个件把它倒过来装上你会发现,咦??我的底盘低了好多。对就是这样你的底盘调整的更低更有赛车的样子了。至此所有的机械结构基本调整完毕。特别提醒,前后底盘的连接一定要在底盘的上部连接否则你会很不开心,会遇到各种问题,尽量做到的就是用最少的料让前后的底盘连接的最稳定。在此不多做介绍了。

以下这种固定方法是不可取的。


舵机拉杆效果图


整车的结构效果图


   接下来就应该说说软件部分了,第一个就是摄像头图像采集问题,个人用过OV7620,蓝宙捕食者3代,山外鹰眼硬件二值化(不要问我为什么做了两次用了三种摄像头)。这个图像采集的问题呢,我觉得很值得一提,我首先介绍一下三种摄像头吧,7620这款摄像头是最经典的一种摄像头,30帧每秒COMS传感器,个人认为用这个摄像头做到3m/s的大神真的是太牛逼了,这个摄像头如果想要用首先你必须有很强的图像处理能力,因为它采集速度慢,图像质量很渣,个人用它跑到的最大速度是2.2m/s。再就是蓝宙捕食者3代,这个不吹不黑,个人感觉是最渣最渣的一款摄像头,会出现各种各样的问题,而且你不知道该怎么去做,不推荐使用。接下来就是重头戏山外鹰眼摄像头,我采用的是60*80像素,采集速度是148帧每秒,采集速度都快比线性CCD快了。它的噪声如何呢,个人测试过没有滤波算法跑到了3m/s的速度,不解释。这个摄像头首先个人觉得需要一个比较大的广角镜头,其次就是前瞻的远处1.2M就足够了,当然也可以用1.4m个人喜好问题和算法问题。这个摄像头属于动态的阈值,阈值可以通过一个参数进行修改,这个自己多看看山外鹰眼摄像头的介绍就知道了。然后还有一个比较头疼的问题就是不能用山外直接给的摄像头采集程序否则达不到148帧/s这部分只能靠自己去研究时序然后改正了,思路呢就是在初始化的时候直接初始化所有的中断源,然后用DMA一只采集可以实现理论上的图像处理与图像采集的并行执行。这部分是很重要的当你的采集速度达到148帧/s后车速达到3m/s你每个图像冲出去的距离也不过2.03cm,这样相对于7620就有了一个明显的优势,你可以提高你的极限速度,如果7620跑3m/s你可以跑到更高。

  赛道模式识别,这部分是很多人最头疼的部分,我也走过很多的弯路,在处理十字的时候自己看着图像看了一个月的时间最后才解决的,还有就是弯道如何识别,什么入弯什么出弯都是什么情况,本人介绍的方法都是按照我以上介绍的配置才适用的,我问过很多司机师傅问他们怎么开车,他们给的回答都很模糊,那么我们是怎么看的呢,我的理解就是我们看的实际上就可以理解为直线和弯道的分量,当前的图像中直线的分量是多少,只要我能够提取出来这个分量我就能得到很好地一个模糊的数值去控制当前的电机转速(个人认为赛道类型就是用来控制电机转速的),那我是怎么做到的识别出来这个分量的呢?我应用了三种方式,第一个就是采用《两点算法求智能车赛道曲率》-蒋旭 吴涛 论文中的计算曲率算法计算了赛道前部和后部的曲率,更信任前部分的曲率,然后加上有效行数据,有效行数据与赛道类型建立一个三次函数的映射关系求出其所占的权重,这样三个算法算出来的数值所占的权重不同最终就能得到一个当前赛道直线分量的权重,得到这个权重后就能通过模糊的方式控制电机了。个人采用的是三次函数映射,在过弯的时候能够达到很好地效果,不会出现不连续的现象,这样就能有一个很好的系统响应。具体算法需要自己去写了,

这是屏幕显示的部分,当时在十字问题卡主的时候这个时候提取出来了直线的分量。

在此我贴一部分代码

     //找到A B C三个点   对应于  《两点算法求智能车赛道曲率》-蒋旭 吴涛 论文中的 图 1 
      Down_A_hang=left_line[0][0];//A点所在行数
      Down_A_lie=left_line[1][0];//A点所在列数
      Down_C_hang=left_line[0][(60-youxiaohang)/2];//C点所在行数
      Down_C_lie=left_line[1][(60-youxiaohang)/2];//C点所在列数
      L_AB=Down_C_hang-Down_A_hang;//求出 L_AB
      L_BC=abs(Down_C_lie-Down_A_lie);//求出 L_BC
      R_qulv=L_AB*L_AB/(2.0*L_BC)+L_BC/2.0;//计算出当前赛道的曲率半径
      //////////
      Down_A1_hang=left_line[0][1];//A点所在行数
      Down_A1_lie=left_line[1][1];//A点所在列数
      Down_C1_hang=left_line[0][((60-youxiaohang)/2)/2+1];//C点所在行数
      Down_C1_lie=left_line[1][((60-youxiaohang)/2)/2+1];//C点所在列数
      L_AB=Down_C_hang-Down_A_hang;//求出 L_AB
      L_BC=abs(Down_C_lie-Down_A_lie);//求出 L_BC
      R_qulv=L_AB*L_AB/(2.0*L_BC)+L_BC/2.0+R_qulv;//计算出当前赛道的曲率半径
      /////////
      Down_A2_hang=left_line[0][2];//A点所在行数
      Down_A2_lie=left_line[1][2];//A点所在列数
      Down_C2_hang=left_line[0][((60-youxiaohang)/2)/2+2];//C点所在行数
      Down_C2_lie=left_line[1][((60-youxiaohang)/2)/2+2];//C点所在列数
      L_AB=Down_C_hang-Down_A_hang;//求出 L_AB
      L_BC=abs(Down_C_lie-Down_A_lie);//求出 L_BC
      R_qulv=L_AB*L_AB/(2.0*L_BC)+L_BC/2.0+R_qulv;//计算出当前赛道的曲率半径
      R_qulv=R_qulv/3.0;//三个点取平均

这部分是我代码中的一部分,当然需要你们自己去做后面的工作,如果有兴趣欢迎联系qq:792499178.

应用此算法后在实际实践中将车子的速度从2.2达到了2.6m/s这时候又出现了一个新的问题就是舵机出现了抖动(抖动情况可以去看QQ空间上面写的那个号网址

 http://mobile.qzone.qq.com/l?g=1336&appid=311&subtype=0&blog_photo=0&ciphertext=28AE2E611D3234CC4EED2BE09951BC60&uw=792499178&g_f=2000000393 
)以上是赛道类型识别模糊算法。

  接下来就是说说控制算法了,控制算法的话我跟其他人应该没什么太大的区别舵机PD,电机PID。首先讲讲PID吧,PID的话就是P-比例,I-积分,D-微分,三个部分组成,这个算法的提出是在很久以前了,具体是谁提出的自行百度吧。在这里首先说说我电机闭环采用的是增量式PID算法,代码呢在这里给大家贴出来

s8  dspeed;
u32 speed_set;
s16 speed_set_base;
s16 Speed_Error=0;
s16 LastSpeed_Error=0;
s16 PrevSpeed_Error=0;
s32 SpeedOut=500000; //电机PWM
s32 LastSpeedOut=500000;
s32 SpeedOut1=0;
extern u8 Start_line;
extern u8 roadflag;
s32 car_speed=0;
extern u8 dispay_on;
void car_speed_control(s16 car_speed_set,u32 Moto_P,u32 Moto_I,u32 Moto_D)

   car_speed=LPTMR0_CNR;
   lptmr_counter_clean(); 
   s16 Speed_ErrorMax=50;
   s16 Speed_ErrorMin=-50;
  Speed_Error=car_speed_set-car_speed;
  if (Speed_Error>Speed_ErrorMax)Speed_Error=Speed_ErrorMax;
  else if (Speed_Error<Speed_ErrorMin)Speed_Error=Speed_ErrorMin;
  SpeedOut=LastSpeedOut+ Moto_P*(Speed_Error-LastSpeed_Error)+ Moto_I*Speed_Error+Moto_D*(Speed_Error+PrevSpeed_Error-2*LastSpeed_Error);        
    if(SpeedOut>dianji_PWM_MAX) 
  {
    SpeedOut=dianji_PWM_MAX;   
  }
  else if(SpeedOut<dianji_PWM_MIN) 
  {
    SpeedOut=dianji_PWM_MIN;
  }


  if (SpeedOut>0)
  {SpeedOut1=SpeedOut;
   FTM_PWM_Duty(FTM0,CH2,0);
   FTM_PWM_Duty(FTM0,CH0,SpeedOut1);
  }
  else
  {
    SpeedOut1=-SpeedOut;
    FTM_PWM_Duty(FTM0,CH2,SpeedOut1);
    FTM_PWM_Duty(FTM0,CH0,0);
  }
  PrevSpeed_Error = LastSpeed_Error;
  LastSpeedOut=SpeedOut;
  LastSpeed_Error=Speed_Error;  
}

这就是我用的增量式PID算法,为什么应用增量式PID算法呢,其实我也不是很明白就是感觉它好吧(个人是光电工程专业的我属于不务正业的那伙所以还请专业人士勿喷),当然也不是完全的没有根据,大家可以百度一下位置式PID和增量式PID两种算法的区别,很容易比较出来哪个有优势。在接下来就是在增量式PID的基础上加了一个棒棒算法,这个实际上是我没有调好的,个人能力问题对PID算法没有理解到很好所以加了棒棒算法后整个车加速的速度很快但是声音特别大(但是个人听起来感觉很爽,如果调好了声音是很小的),棒棒算法是什么呢就是当你编码器返回的速度与你预期速度差距很大的时候直接满占空比输出,这样可以让你的车很快的达到目标速度(这就是对应于之前我那个机械结构的设计,在后轮调整中有提到),测试后可以在参数一般的情况下2m的距离内加速到10ms,250个脉冲的速度(采用的512线的迷你编码器),这个根据车模不同有不同的数值,这里的数据仅供参考。接下来就介绍一下舵机PD的参数设定了,这个参数难倒了智能车的大部分人在这里我就透露我的一些经验吧,首先我采用的是P三次函数算法,自变量是有效行,因变量是P的值,当然更建议的是自己设定P值,首先找到一个效果比较好的函数映射曲线后在用matlab进行拟合取出来相应的数值后用数组的形式导入到程序中,在根据调试的情况具体情况具体分析后在微调数组中的P值,然后D值的选取呢,当你的车速度没有超过2.6m/s之前个人认为没有必要用这个参数,为什么这么说呢,因为我在2.2m/s的时候完全不会出现抖动的情况,当速度提升后在直线时候舵机抖动厉害,这个时候就需要D的值了,这个D值作用是什么呢?它的作用就是放大偏差,有人会说放大偏差干什么,个人的理解是变相的一种闭环,当速度大的时候惯性比较大拐弯不是很容易,当你需要拐的角度越大需要的力就越大,这样就可以体现出来D值的重要性,通常D值根据拐弯的大小即赛道类型而变化个人采用的是与P值成一定的正比例关系。采用这个方式后车子的速度提升到了3m/s,从2.2m/s到3m/s一共用了2天时间。

下面我留下我的舵机P算法

 float Kp = (CAMERA_H - info->effectiveLine)*(CAMERA_H - info->effectiveLine)/gServoPid.coefficient+gServoPid.p;
outPWM = (int32_t)(Kp*info->error + gServoPid.d*(info->error - gServoPid.error1)) + gCarParam.servoCenter; gServoPid.error1 = info->error;

具体参数自己慢慢调。有兴趣的可以联系上面的qq,或联系BaiYH1994@163.com.


  个人认为智能车摄像头组大体上我涉及的就只有这些了,还有一些细节问题我没有提过,这些就需要自己去创新了,目标只有一个,但是过程我们可以有上百上千种,以上是我的方法,如果有错误的地方还请各位大神指正,也希望能够帮助新手了解一下智能车的一些知识。


2016.11.8    22:44

白银浩

2013-04-24 20:28:00 xiaowei_cqu 阅读数 6277

近来经常和心理系做实验,总是有各种“什么什么随机化,刺激的物理性质保持一样。。”的需求。之前做《去掩蔽》的实验时,有一套图片就是做的像素随机化,这是最简单的随机化了。当时图像只有两种像素,灰的和深灰的,而且深灰的比较少。


于是我就统计了深灰像素点的个数,然后在一张同样大的灰色图片中的随机位置洒深灰像素点。

int pix_count=0;
	for(int i=0;i<img_width+eye_shift;i++){
		uchar* p=sub_masker.ptr<uchar>(i);
		for(int j=0;j<img_width+eye_shift;j++){
			if(p[j*3]==78){
				pix_count++;
			}
		}
	}
	//cout<<pix_count<<endl;
	int pix_width=img_width+eye_shift;
	while(pix_count>0){
		int rand_x=rand()%pix_width;
		int rand_y=rand()%pix_width;
		uchar* p_pix=pix_masker.ptr<uchar>(rand_x);
		if(p_pix[rand_y*3]==128){
			p_pix[rand_y*3]=78;
			p_pix[rand_y*3+1]=78;
			p_pix[rand_y*3+2]=78;
			pix_count--;
			//	cout<<pix_count<<endl;
		}
	}

大致效果如上图(*忽略几个字母,是叠加了目标刺激的效果)。

但这次需要对一个刺激视频中每一帧做随机化,且视频是彩色的。

我一开始的思路是对像素中每一个点,随机找另外一个点交换他们的RGB值。
		Mat frame_copy(frame_rows,fram_cols, CV_8UC3,Scalar(0,0,0));
		frame.copyTo(frame_copy);
		Mat frame_tag=Mat::zeros(frame_rows,fram_cols, CV_8UC1);
		for(int i=0;i<frame_rows;i++){
			uchar* p=frame_copy.ptr<uchar>(i);
			for(int j=0;j<fram_cols;j+=3){
				uchar r=p[0];
				uchar b=p[1];
				uchar g=p[2];
				int rand_row=rand()%frame_rows;
				int rand_col=rand()%fram_cols;
			//	cout<<rand_row<<" "<<rand_col<<endl;
				uchar* rand_p=frame_copy.ptr<uchar>(rand_row);
				p[0]=rand_p[rand_col*3+0];
				p[1]=rand_p[rand_col*3+1];
				p[2]=rand_p[rand_col*3+2];
				rand_p[rand_col*3+0]=r;
				rand_p[rand_col*3+1]=b;
				rand_p[rand_col*3+2]=g;
			}
		}

但不知为何,实现出来的效果是这样的。。。
莫不是因为每个点都被随机了,在后面的时候又以一定的概率被随机回去了???

于是还是改成了原来撒点的思路,对应新建一幅一样大的黑色图,逐点读取原图的像素点,如果遇到非黑色的点,就在新图随机找一个黑色的(也就是未被修改过的点)修改像素值为原图中此点的像素值。
完整代码:
int main(){
	VideoCapture inputVideo("情绪学习.wmv");
	if ( !inputVideo.isOpened()){
		cout << "Could not open the input video."  << endl;
		return -1;
	}
	Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
		(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
	int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // Get Codec Type- Int form
	VideoWriter outputVideo; // Open the output
	outputVideo.open("ZhongXing.wmv",CV_FOURCC('M','J','P','G'), 30,S, true);
	srand((unsigned)time(NULL));
	int frame_count=0;
	while(true){
		Mat frame;
		inputVideo>>frame;
		if(frame.empty())
			break;
		int frame_rows=frame.rows;
		int fram_cols=frame.cols;
		Mat frame_copy(frame_rows,fram_cols, CV_8UC3,Scalar(0,0,0));
		Mat frame_tag=Mat::zeros(frame_rows,fram_cols, CV_8UC1);
		for(int i=0;i<frame_rows;i++){
			uchar* p_frame=frame.ptr<uchar>(i);
			for(int j=0;j<fram_cols;j+=3){
				uchar r=p_frame[j+0];
				uchar b=p_frame[j+1];
				uchar g=p_frame[j+2];
				if((r>0)||(b>0)||(g>0)){
					bool if_tag=false;
					while(!if_tag){
						int rand_row=rand()%frame_rows;
						int rand_col=rand()%fram_cols;
						uchar* p_tag=frame_tag.ptr<uchar>(rand_row);
						uchar* p_copy=frame_copy.ptr<uchar>(rand_row);
						if(p_tag[rand_col]==1)
							continue;
						else{
							p_tag[rand_col]=1;
							p_copy[rand_col*3+0]=r;
							p_copy[rand_col*3+1]=b;
							p_copy[rand_col*3+2]=g;
							if_tag=true;
						}
					}
				}
			}
		}
		cout<<"Write frame: "<<frame_count++<<endl;
		outputVideo<<frame_copy;
	}
	cout<<"Finished Writing"<<endl;
	return 0;
}

然后就实现了漫天飞舞的随机雪花效果啦~





(转载请注明作者和出处:http://blog.csdn.net/xiaowei_cqu 未经允许请勿用于商业用途)



2013-04-24 20:28:00 iteye_18800 阅读数 22

近来经常和心理系做实验,总是有各种“什么什么随机化,刺激的物理性质保持一样。。”的需求。之前做《去掩蔽》的实验时,有一套图片就是做的像素随机化,这是最简单的随机化了。当时图像只有两种像素,灰的和深灰的,而且深灰的比较少。


于是我就统计了深灰像素点的个数,然后在一张同样大的灰色图片中的随机位置洒深灰像素点。

int pix_count=0;
	for(int i=0;i<img_width+eye_shift;i++){
		uchar* p=sub_masker.ptr<uchar>(i);
		for(int j=0;j<img_width+eye_shift;j++){
			if(p[j*3]==78){
				pix_count++;
			}
		}
	}
	//cout<<pix_count<<endl;
	int pix_width=img_width+eye_shift;
	while(pix_count>0){
		int rand_x=rand()%pix_width;
		int rand_y=rand()%pix_width;
		uchar* p_pix=pix_masker.ptr<uchar>(rand_x);
		if(p_pix[rand_y*3]==128){
			p_pix[rand_y*3]=78;
			p_pix[rand_y*3+1]=78;
			p_pix[rand_y*3+2]=78;
			pix_count--;
			//	cout<<pix_count<<endl;
		}
	}

大致效果如上图(*忽略几个字母,是叠加了目标刺激的效果)。

但这次需要对一个刺激视频中每一帧做随机化,且视频是彩色的。

我一开始的思路是对像素中每一个点,随机找另外一个点交换他们的RGB值。
		Mat frame_copy(frame_rows,fram_cols, CV_8UC3,Scalar(0,0,0));
		frame.copyTo(frame_copy);
		Mat frame_tag=Mat::zeros(frame_rows,fram_cols, CV_8UC1);
		for(int i=0;i<frame_rows;i++){
			uchar* p=frame_copy.ptr<uchar>(i);
			for(int j=0;j<fram_cols;j+=3){
				uchar r=p[0];
				uchar b=p[1];
				uchar g=p[2];
				int rand_row=rand()%frame_rows;
				int rand_col=rand()%fram_cols;
			//	cout<<rand_row<<" "<<rand_col<<endl;
				uchar* rand_p=frame_copy.ptr<uchar>(rand_row);
				p[0]=rand_p[rand_col*3+0];
				p[1]=rand_p[rand_col*3+1];
				p[2]=rand_p[rand_col*3+2];
				rand_p[rand_col*3+0]=r;
				rand_p[rand_col*3+1]=b;
				rand_p[rand_col*3+2]=g;
			}
		}

但不知为何,实现出来的效果是这样的。。。
莫不是因为每个点都被随机了,在后面的时候又以一定的概率被随机回去了???

于是还是改成了原来撒点的思路,对应新建一幅一样大的黑色图,逐点读取原图的像素点,如果遇到非黑色的点,就在新图随机找一个黑色的(也就是未被修改过的点)修改像素值为原图中此点的像素值。
完整代码:
int main(){
	VideoCapture inputVideo("情绪学习.wmv");
	if ( !inputVideo.isOpened()){
		cout << "Could not open the input video."  << endl;
		return -1;
	}
	Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
		(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
	int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // Get Codec Type- Int form
	VideoWriter outputVideo; // Open the output
	outputVideo.open("ZhongXing.wmv",CV_FOURCC('M','J','P','G'), 30,S, true);
	srand((unsigned)time(NULL));
	int frame_count=0;
	while(true){
		Mat frame;
		inputVideo>>frame;
		if(frame.empty())
			break;
		int frame_rows=frame.rows;
		int fram_cols=frame.cols;
		Mat frame_copy(frame_rows,fram_cols, CV_8UC3,Scalar(0,0,0));
		Mat frame_tag=Mat::zeros(frame_rows,fram_cols, CV_8UC1);
		for(int i=0;i<frame_rows;i++){
			uchar* p_frame=frame.ptr<uchar>(i);
			for(int j=0;j<fram_cols;j+=3){
				uchar r=p_frame[j+0];
				uchar b=p_frame[j+1];
				uchar g=p_frame[j+2];
				if((r>0)||(b>0)||(g>0)){
					bool if_tag=false;
					while(!if_tag){
						int rand_row=rand()%frame_rows;
						int rand_col=rand()%fram_cols;
						uchar* p_tag=frame_tag.ptr<uchar>(rand_row);
						uchar* p_copy=frame_copy.ptr<uchar>(rand_row);
						if(p_tag[rand_col]==1)
							continue;
						else{
							p_tag[rand_col]=1;
							p_copy[rand_col*3+0]=r;
							p_copy[rand_col*3+1]=b;
							p_copy[rand_col*3+2]=g;
							if_tag=true;
						}
					}
				}
			}
		}
		cout<<"Write frame: "<<frame_count++<<endl;
		outputVideo<<frame_copy;
	}
	cout<<"Finished Writing"<<endl;
	return 0;
}

然后就实现了漫天飞舞的随机雪花效果啦~





(转载请注明作者和出处:http://blog.csdn.net/xiaowei_cqu未经允许请勿用于商业用途)



没有更多推荐了,返回首页