动态规划之初见0-1背包

本文详细解析了0-1背包问题与装箱问题的算法实现过程,包括如何通过动态规划寻找最优解,旨在帮助读者理解并掌握这两类经典问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0-1背包问题:

问题描述:有n件物品x1, x2, …, xn ,每件物品有一个价值和一个重量,分别记为:

   v1,v2,…vn

  w1,w2,…wn

其中所有的wi均为整数。现有一个背包,其最大载重量为C,要求从这n件物品中任取若干件(这些物品要么被装入要么被留下)。问背包中装入哪些物品可使得所装物品的价值和最大?

例如,C=10, n = 5,

  V[n]={063546}

  w[n]={022654}



#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

int arr[100][100] ;
int maxw, num;
int value[100],weight[100];
int result[100];

void setArr()
{
	//先放最后一个物品 
	for(int i = 1; i<=maxw; i++)
	{
		if(i > weight[num])
		{
			arr[num][i] = value[num];
		}
	}
	
	for(int i = num-1; i>0; i--)
	{
		for(int j = 1; j<=maxw; j++)
		{
			if(j<value[j])  //放不下 
			{
				arr[i][j] = arr[i+1][j];
			}
			else //放得下 
			{
				if( ( arr[i+1][j-weight[i]] + value[i] ) > arr[i+1][j] )
				{
					arr[i][j] = arr[i+1][j-weight[i]] + value[i];
				} 
				else
				{
					arr[i][j] = arr[i+1][j];
				}
			} 
		}
	} 
}

void findAns()
{
	int j = maxw;
	for(int i = 1; i<=num; i++)
	{
		if(arr[i][j] == arr[i+1][j])
		{
			result[i] = 0;
		}
		else
		{
			result[i] = 1;
			j -= weight[i];
		}
	}
} 

int main() {
	cin>>maxw>>num;
	for(int i = 1; i<num+1; i++)
	{
		cin>>value[i]>>weight[i]; 
	}
	memset(arr, 0, sizeof(int));
	
	setArr();
	findAns();
	int maxv = 0, totalw = 0;
	for(int i = 1; i<num+1; i++)
	{
		if(result[i]==1)
		{
			maxv += value[i];
			totalw += weight[i];
		}
		cout<<"物品"<<i<<":"<<result[i]<<" "; 
	}
	cout<<endl;
	cout<<endl<<"总重:"<<totalw<<"  总价值:"<<maxv<<endl;
	return 0;
}




装箱问题

[问题描述]    有一个箱子容量为v(正整数,0≤v≤20000),同时有n个物品(0≤n≤30),每个物品有一个体积(正整数)。要求从n个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。

[样例]输入:

  24      一个整数,表示箱子容量

  6       一个整数,表示有n个物品

  8       接下来n行,分别表示这n个物品的各自体积。

  3

  12

  7

  9

  7

输出:         0       一个整数,表示箱子剩余空间。

#include <iostream>
#include <string.h>
using namespace std;

int space,num;
int weig[31];
int bag[31][20001]; //标号为0不用 

void fillbag()
{
	for(int j = 1; j <= space; j++)  //先放最后一层 
	{
		if(j >= weig[num] )
		{
			bag[num][j] = weig[num]; 
		} 
	}
	
	for(int i = num-1; i>0; i--)
	{
		for(int j = 1; j <= space; j++)
		{
			if( weig[i] > j )
			{
				bag[i][j] = bag[i+1][j];
			}
			else if( (weig[i] + bag[i+1][j-weig[i]]) > bag[i+1][j])
			{
				bag[i][j] = weig[i] + bag[i+1][j-weig[i]];
			}
			else
			{
				bag[i][j] = bag[i+1][j];
			}
		}
	} 
}

int findans()
{
	int total = 0;
	int weight = space;
	for(int i = 1; i<num+1; i++)
	{
		if(bag[i][weight] != bag[i+1][weight])
		{
			total += weig[i];
			weight -= weig[i];
		}
	}
	return total;
}

int main() {
	cin>>space>>num;
	memset(weig, 0, sizeof(weig));
	memset(bag, 0, sizeof(bag));
	for(int i = 1; i<=num; i++)
	{
		cin>>weig[i];
	}
	
	fillbag();
	int total = findans();	
	cout<<space-total<<endl;
	return 0;
}
思想一样



#include "images.h" uint8 l_border[MT9V03X_H];//左线数组 uint8 r_border[MT9V03X_H];//右线数组 uint8 center_line[MT9V03X_H];//中线数组 /*变量声明*/ //uint8 original_image[MT9V03X_H][MT9V03X_W]; uint8 bin_image[MT9V03X_H][MT9V03X_W];//图像数组 uint8 image_thereshold_last = 0;// uint8 image_thereshold;//图像分割阈值 //------------------------------------------------------------------------------------------------------------------ // @函数功能 求绝对值 // @函数返回 绝对值 //------------------------------------------------------------------------------------------------------------------ int my_abs(int value) { if(value>=0) return value; else return -value; } //数值范围限制 int16 limit_a_b(int16 x, int a, int b) { if(x<a) x = a; if(x>b) x = b; return x; } //------------------------------------------------------------------------------------------------------------------ // @函数功能 求x,y中的最小值 // @函数返回 两值中的最小值 //------------------------------------------------------------------------------------------------------------------ int16 limit1(int16 x, int16 y) { if (x > y) return y; else if (x < -y) return -y; else return x; } //------------------------------------------------------------------------------------------------------------------ // @函数功能 获得一副灰度图像 // @函数返回 灰度图像数组original_image //------------------------------------------------------------------------------------------------------------------ void Get_image(uint8(*mt9v03x_image)[MT9V03X_W]) { uint8 i = 0, j = 0; for (i = 0; i < MT9V03X_H; i += 1) { for (j = 0; j <MT9V03X_W; j += 1) { bin_image[i][j] = mt9v03x_image[i][j]; } } } //将原始图像复制到bin_image数组 //------------------------------------------------------------------------------------------------------------------ // @函数功能 大津法求动态阈值 // @函数返回 动态阈值Threshold //------------------------------------------------------------------------------------------------------------------ uint8 OtsuThreshold(uint8 *image) { uint8 Pixel_Max = 0; uint8 Pixel_Min = 255; //uint16 width = MT9V03X_W / use_num; //uint16 height = MT9V03X_H / use_num; int pixelCount[GrayScale]; //各像素GrayScale的个数pixelCount 一维数组 float pixelPro[GrayScale]; //各像素GrayScale所占百分比pixelPro 一维数组 int16 i = 0; int16 j = 0; int16 pixelSum = MT9V03X_W * MT9V03X_H / 4; //pixelSum是获取总的图像像素个数的1/4,相应下面轮询时高宽都是以2为单位自增 uint8 threshold = 0; uint8* data = image; //指向像素数据的指针 for(i = 0;i < GrayScale;i++) { pixelCount[i] = 0; pixelPro[i] = 0; } uint32 gray_sum = 0; //统计灰度图中每个像素在整幅图像中的个数 for(i = 0;i < MT9V03X_H;i += 2) { for(j = 0;j < MT9V03X_W; j += 2) { pixelCount[(int)data[i * MT9V03X_W + j]]++; //将当前的点的像素值作为计数数组的下标 gray_sum += (int)data[i * MT9V03X_W + j]; //灰度值总 if(data[i * MT9V03X_W + j] > Pixel_Max) { Pixel_Max = data[i * MT9V03X_W + j]; } if(data[i * MT9V03X_W + j] < Pixel_Min) { Pixel_Min = data[i * MT9V03X_W + j]; } } } //计算每个像素值的点在整幅图像中的比例 for(i = Pixel_Min;i < Pixel_Max;i++) { pixelPro[i] = (float)pixelCount[i] / pixelSum; } //遍历灰度值 float w0,w1,u0tmp,u1tmp,u0,u1,deltaTmp,deltaMax = 0; w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0; for(j = Pixel_Min;j < Pixel_Max;j++) { w0 += pixelPro[j]; //背景部分每个灰度值的像素点所占比例之 即背景部分的比例 u0tmp += j * pixelPro[j]; //背景部分 每个灰度值的点的比例 *灰度值 w1 = 1 - w0; u1tmp = gray_sum / pixelSum-u0tmp; u0 = u0tmp / w0; //背景平均灰度 u1 = u1tmp / w1; //前景平均灰度 deltaTmp = (float)(w0 * w1 * (u0 - u1) * (u0 - u1)); if(deltaTmp > deltaMax) { deltaMax = deltaTmp; threshold = (uint8)j; } if(deltaTmp < deltaMax) { break; } } //限幅 if(threshold > 25 && threshold < 235) { image_thereshold_last = threshold; } else { threshold = image_thereshold_last; } return threshold; } //------------------------------------------------------------------------------------------------------------------ // @函数功能 图像二值化,大津法 // @函数返回 二值化图像数组bin_image //------------------------------------------------------------------------------------------------------------------ void turn_to_bin(void) { uint8 i,j; image_thereshold = OtsuThreshold(bin_image[0]); //ips114_show_int(189,0,image_thereshold,5); for(i = 0;i < MT9V03X_H;i++) { for(j = 0;j < MT9V03X_W;j++) { if(bin_image[i][j] > image_thereshold) { bin_image[i][j] = 255; } else { bin_image[i][j] = 0; } } } /* for(i = 40;i < MT9V03X_H;i++) { for(j = 0;j < MT9V03X_W;j++) { if(bin_image[i][j] < image_thereshold) { bin_image[i][j] = 0; } else { bin_image[i][j] =255; } } }*/ } //------------------------------------------------------------------------------------------------------------------ // @函数功能 寻找两个边界的边界点作为八邻域循环的起始点 // @参数说明 输入任意行数 // @函数返回 无 //------------------------------------------------------------------------------------------------------------------ uint8 start_point_l[2] = { 0 };//左边起点的x,y值 uint8 start_point_r[2] = { 0 };//右边起点的x,y值 uint8 get_start_point(uint8 start_row) { uint8 i = 0,j = MT9V03X_W/2,l_found = 0,r_found = 0,num = 0; //清零 start_point_l[0] = 0;//左x start_point_l[1] = 0;//左y start_point_r[0] = 0;//右x start_point_r[1] = 0;//右y //大致定位白线 for(num = 0;num < MT9V03X_W/2 - 15;num = num + 10) { if(bin_image[start_row][j + num] == 255) { j = j + num; break; } if(bin_image[start_row][j - num] == 255) { j = j - num; break; } } //从中间往左边,先找起点 for (i = j; i > border_min; i--) { start_point_l[0] = i;//x start_point_l[1] = start_row;//y if (bin_image[start_row][i] == 255 && bin_image[start_row][i - 1] == 0) { //printf("找到左边起点image[%d][%d]\n", start_row,i); l_found = 1; break; } } for (i = j; i < border_max; i++) { start_point_r[0] = i;//x start_point_r[1] = start_row;//y if (bin_image[start_row][i] == 255 && bin_image[start_row][i + 1] == 0) { //printf("找到右边起点image[%d][%d]\n",start_row, i); r_found = 1; break; } } if(l_found&&r_found) { return 1; } else { //printf("未找到起点\n"); return 0; } } //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // @函数功能 八邻域正式开始找右边点的函数,左右线一次性找完。 Tip:特别注意,不要拿宏定义名字作为输入参数,否则数据可能无法传递过来 // @参数说明 // break_flag_r 最多需要循环的次数 // (*image)[image_w] 需要进行找点的图像数组,必须是二值图,填入数组名称即可 // *l_stastic 统计左边数据,用来输入初始数组成员的序号取出循环次数 // *r_stastic 统计右边数据,用来输入初始数组成员的序号取出循环次数 // l_start_x 左边起点横坐标 // l_start_y 左边起点纵坐标 // r_start_x 右边起点横坐标 // r_start_y 右边起点纵坐标 // hightest 循环结束所得到的最高高度 // @函数返回 无 // @备 注: //example:search_l_r((uint16)USE_num,image,&data_stastics_l, &data_stastics_r,start_point_l[0],start_point_l[1], start_point_r[0], start_point_r[1],&hightest); //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #define USE_num MT9V03X_H*3 //定义找点的数组成员个数按理说300个点能放下,但是有些特殊情况确实难顶,多定义了一点 //存放点的x,y坐标 uint16 points_l[(uint16)USE_num][2] = { { 0 } };//左线 uint16 points_r[(uint16)USE_num][2] = { { 0 } };//右线 uint16 dir_r[(uint16)USE_num] = { 0 };//用来存储右边生长方向 uint16 dir_l[(uint16)USE_num] = { 0 };//用来存储左边生长方向 uint16 data_stastics_l = 0;//统计左边找到点的个数 uint16 data_stastics_r = 0;//统计右边找到点的个数 uint8 hightest = 0;//最高点 void search_l_r(uint16 break_flag, uint8(*image)[MT9V03X_W], uint16 *l_stastic, uint16 *r_stastic, uint8 l_start_x, uint8 l_start_y, uint8 r_start_x, uint8 r_start_y, uint8*hightest) { uint8 i = 0, j = 0; //左边变量 uint8 search_filds_l[8][2] = { { 0 } }; uint8 index_l = 0; uint8 temp_l[8][2] = { { 0 } }; uint8 center_point_l[2] = { 0 }; uint16 l_data_statics;//统计左边 //定义八个邻域 static int8 seeds_l[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1},}; //{-1,-1} {0,-1} {+1,-1} //{-1, 0} {+1, 0} //{-1,+1} {0,+1} {+1,+1} //顺时针 //右边变量 uint8 search_filds_r[8][2] = { { 0 } }; uint8 center_point_r[2] = { 0 };//中心坐标点 uint8 index_r = 0;//索引下标 uint8 temp_r[8][2] = { { 0 } }; uint16 r_data_statics;//统计右边 //定义八个邻域 static int8 seeds_r[8][2] = { {0,1},{1,1},{1,0}, {1,-1},{0,-1},{-1,-1}, {-1,0},{-1,1}, }; //{-1,-1} {0,-1} {+1,-1}, //{-1, 0} {+1, 0} //{-1,+1} {0,+1} {+1,+1} //这个是逆时针 l_data_statics = *l_stastic;//统计找到了多少个点,方便后续把点全部画出来 r_data_statics = *r_stastic;//统计找到了多少个点,方便后续把点全部画出来 //第一次更新坐标点 将找到的起点值传进来 center_point_l[0] = l_start_x;//x center_point_l[1] = l_start_y;//y center_point_r[0] = r_start_x;//x center_point_r[1] = r_start_y;//y //开启邻域循环 while (break_flag--) { //左边 for (i = 0; i < 8; i++)//传递8F坐标 { search_filds_l[i][0] = center_point_l[0] + seeds_l[i][0];//x search_filds_l[i][1] = center_point_l[1] + seeds_l[i][1];//y } //中心坐标点填充到已经找到的点内 points_l[l_data_statics][0] = center_point_l[0];//x points_l[l_data_statics][1] = center_point_l[1];//y l_data_statics++;//索引加一 //右边 for (i = 0; i < 8; i++)//传递8F坐标 { search_filds_r[i][0] = center_point_r[0] + seeds_r[i][0];//x search_filds_r[i][1] = center_point_r[1] + seeds_r[i][1];//y } //中心坐标点填充到已经找到的点内 points_r[r_data_statics][0] = center_point_r[0];//x points_r[r_data_statics][1] = center_point_r[1];//y index_l = 0;//先清零,后使用 for (i = 0; i < 8; i++) { temp_l[i][0] = 0;//先清零,后使用 temp_l[i][1] = 0;//先清零,后使用 } //左边判断 for (i = 0; i < 8; i++) { if (image[search_filds_l[i][1]][search_filds_l[i][0]] == 0 && image[search_filds_l[(i + 1) & 7][1]][search_filds_l[(i + 1) & 7][0]] == 255) { temp_l[index_l][0] = search_filds_l[(i)][0]; temp_l[index_l][1] = search_filds_l[(i)][1]; index_l++; dir_l[l_data_statics - 1] = (i);//记录生长方向 } if (index_l) { //更新坐标点 center_point_l[0] = temp_l[0][0];//x center_point_l[1] = temp_l[0][1];//y for (j = 0; j < index_l; j++) { if (center_point_l[1] > temp_l[j][1]) { center_point_l[0] = temp_l[j][0];//x center_point_l[1] = temp_l[j][1];//y } } } } if ((points_r[r_data_statics][0]== points_r[r_data_statics-1][0]&& points_r[r_data_statics][0] == points_r[r_data_statics - 2][0] && points_r[r_data_statics][1] == points_r[r_data_statics - 1][1] && points_r[r_data_statics][1] == points_r[r_data_statics - 2][1]) ||(points_l[l_data_statics-1][0] == points_l[l_data_statics - 2][0] && points_l[l_data_statics-1][0] == points_l[l_data_statics - 3][0] && points_l[l_data_statics-1][1] == points_l[l_data_statics - 2][1] && points_l[l_data_statics-1][1] == points_l[l_data_statics - 3][1])) { //printf("三次进入同一个点,退出\n"); break; } if (my_abs(points_r[r_data_statics][0] - points_l[l_data_statics - 1][0]) < 2 && my_abs(points_r[r_data_statics][1] - points_l[l_data_statics - 1][1] < 2)) { //printf("\n左右相遇退出\n"); *hightest = (points_r[r_data_statics][1] + points_l[l_data_statics - 1][1]) >> 1;//取出最高点 //printf("\n在y=%d处退出\n",*hightest); break; } if ((points_r[r_data_statics][1] < points_l[l_data_statics - 1][1])) { //printf("\n如果左边比右边高了,左边等待右边\n"); continue;//如果左边比右边高了,左边等待右边 } if (dir_l[l_data_statics - 1] == 7 && (points_r[r_data_statics][1] > points_l[l_data_statics - 1][1]))//左边比右边高且已经向下生长了 { //printf("\n左边开始向下了,等待右边,等待中... \n"); center_point_l[0] = points_l[l_data_statics - 1][0];//x center_point_l[1] = points_l[l_data_statics - 1][1];//y l_data_statics--; } r_data_statics++;//索引加一 index_r = 0;//先清零,后使用 for (i = 0; i < 8; i++) { temp_r[i][0] = 0;//先清零,后使用 temp_r[i][1] = 0;//先清零,后使用 } //右边判断 for (i = 0; i < 8; i++) { if (image[search_filds_r[i][1]][search_filds_r[i][0]] == 0 && image[search_filds_r[(i + 1) & 7][1]][search_filds_r[(i + 1) & 7][0]] == 255) { temp_r[index_r][0] = search_filds_r[(i)][0]; temp_r[index_r][1] = search_filds_r[(i)][1]; index_r++;//索引加一 dir_r[r_data_statics - 1] = (i);//记录生长方向 //printf("dir[%d]:%d\n", r_data_statics - 1, dir_r[r_data_statics - 1]); } if (index_r) { //更新坐标点 center_point_r[0] = temp_r[0][0];//x center_point_r[1] = temp_r[0][1];//y for (j = 0; j < index_r; j++) { if (center_point_r[1] > temp_r[j][1]) { center_point_r[0] = temp_r[j][0];//x center_point_r[1] = temp_r[j][1];//y } } } } } //取出循环次数 *l_stastic = l_data_statics; *r_stastic = r_data_statics; } //------------------------------------------------------------------------------------------------------------------ // @函数功能 从八邻域边界里提取需要的左边线 // @参数说明 total_L :找到的点的总数 // @函数返回 左边线数组l_border //------------------------------------------------------------------------------------------------------------------ uint16 border_to_edge_l[MT9V03X_H];//存放左边borderedge的映射关系的数组 void get_left(uint16 total_L) { uint8 i = 0; uint16 j = 0; uint8 h = 0; //初始化 for (i = 0;i<MT9V03X_H;i++) { l_border[i] = border_min; } h = MT9V03X_H - 2; //左边 for (j = 0; j < total_L; j++) { //printf("%d\n", j); if (points_l[j][1] == h) { l_border[h] = points_l[j][0]+1; border_to_edge_l[h] = j; } else continue; //每行只取一个点,没到下一行就不记录 h--; if (h == 0) { break;//到最后一行退出 } } } //------------------------------------------------------------------------------------------------------------------ // @函数功能 从八邻域边界里提取需要的右边线 // @参数说明 total_R :找到的点的总数 // @函数返回 右边线数组r_border //------------------------------------------------------------------------------------------------------------------ uint16 border_to_edge_r[MT9V03X_H];//存放右边borderedge的映射关系的数组 void get_right(uint16 total_R) { uint8 i = 0; uint16 j = 0; uint8 h = 0; for (i = 0; i < MT9V03X_H; i++) { r_border[i] = border_max;//右边线初始化放到最右边,左边线放到最左边,这样八邻域闭合区域外的中线就会在中间,不会干扰得到的数据 } h = MT9V03X_H - 2; //右边 for (j = 0; j < total_R; j++) { if (points_r[j][1] == h) { r_border[h] = points_r[j][0] - 1; border_to_edge_r[h] = j; } else continue;//每行只取一个点,没到下一行就不记录 h--; if (h == 0)break;//到最后一行退出 } } //------------------------------------------------------------------------------------------------------------------ // @函数功能 滤波减少噪声 // @函数返回 经过滤波的图像数组bin_image //------------------------------------------------------------------------------------------------------------------ #define threshold_max 255*5//定义膨胀的阈值区间 #define threshold_min 255*2//定义腐蚀的阈值区间 void image_filter(uint8(*bin_image)[MT9V03X_W])//形态学滤波,膨胀腐蚀 { uint16 i, j; uint32 num = 0; for (i = 1; i < MT9V03X_H - 1; i++) { for (j = 1; j < (MT9V03X_W - 1); j++) { //统计八个方向的像素值 num = bin_image[i - 1][j - 1] + bin_image[i - 1][j] + bin_image[i - 1][j + 1] + bin_image[i][j - 1] + bin_image[i][j + 1] + bin_image[i + 1][j - 1] + bin_image[i + 1][j] + bin_image[i + 1][j + 1]; if (num >= threshold_max && bin_image[i][j] == 0) { bin_image[i][j] = 255;//白 } if (num <= threshold_min && bin_image[i][j] == 255) { bin_image[i][j] = 0;//黑 } } } } //------------------------------------------------------------------------------------------------------------------ // @函数功能 给图像画一个黑框 // @函数返回 带有黑框的图像数组bin_image //------------------------------------------------------------------------------------------------------------------ void image_draw_rectan(uint8(*image)[MT9V03X_W]) { uint8 i = 0; for (i = 0; i < MT9V03X_H; i++) { image[i][0] = 0; image[i][1] = 0; image[i][MT9V03X_W - 1] = 0; image[i][MT9V03X_W - 2] = 0; } for (i = 0; i < MT9V03X_W; i++) { image[0][i] = 0; image[1][i] = 0; //image[image_h-1][i] = 0; } } //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // @函数功能 环岛元素识别处理 // @函数返回 无 //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //全局状态变量 IslandState current_state = NORMAL; uint8_t island_type = 0; // 0:未确定 1:左环岛 2:右环岛 uint8 target_h = 0;//存放断裂点行数 uint16 A_edge = 0; uint16 V_edge = 0; uint8 A_point = 0; uint8 P_point = 0; uint8 V_point = 0; //------------------------------------------------------------------------------------------------------------------ // @函数功能 边界连续性判断 // @参数说明 需要寻找的边线 // @函数返回 有断裂返回0,无断裂返回1 //------------------------------------------------------------------------------------------------------------------ uint8 border_continuous(uint8 *border) { for(uint8 i = MT9V03X_H-1;i > 0;i--) { int8 diff = border[i] - border[i - 1]; if(diff < -4 || diff > 4) { target_h = i; return 0;//有断裂 } } return 1;//无断裂 } //------------------------------------------------------------------------------------------------------------------ // @函数功能 寻找A点 // @函数返回 A点 //------------------------------------------------------------------------------------------------------------------ //左圆环时寻找左边界A点 uint8 find_point_A_l(void) { uint16 j = border_to_edge_l[target_h];//映射 int16 search_min = j - search_range;//遍历点的最小编号 int16 search_max = j + search_range;//遍历点的最大编号 //限定查找区间 if(search_min < 3) { search_min = 3; } if(search_max > data_stastics_l - 2) { search_max = data_stastics_l - 2; } //遍历寻找A点 for(j = search_min;j <= search_max;j++) { if(points_l[j+2][0]<points_l[j][0] && points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1]) { A_edge = j; return 1;//找到A点 } } return 0;//未找到A点 } //右圆环时寻找右边界A点 uint8 find_point_A_r(void) { uint16 j = border_to_edge_r[target_h];//映射 int16 search_min = j - search_range;//遍历点的最小编号 int16 search_max = j + search_range;//遍历点的最大编号 //限定查找区间 if(search_min < 3) { search_min = 3; } if(search_max > data_stastics_r - 2) { search_max = data_stastics_r - 2; } //遍历寻找A点 for(j = search_min;j <= search_max;j++) { if(points_l[j+2][0]>points_l[j][0] && points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1]) { A_edge = j; return 1;//找到A点 } } return 0;//未找到A点 } //------------------------------------------------------------------------------------------------------------------ // @函数功能 寻找P点 // @函数返回 P点 //------------------------------------------------------------------------------------------------------------------ //左圆环时寻找左边界P点 uint8 find_point_P_l(void) { for(uint8 i = MT9V03X_H - 2;i > 1;i++) { if(l_border[i-2] < l_border[i] && l_border[i+2] < l_border[i]) { P_point = i; return 1;//找到P点 } } return 0;//未找到P点 } //右圆环时寻找左边界P点 uint8 find_point_P_r(void) { for(uint8 i = MT9V03X_H - 2;i > 1;i++) { if(l_border[i-2] > l_border[i] && l_border[i+2] > l_border[i]) { P_point = i; return 1;//找到P点 } } return 0;//未找到P点 } //------------------------------------------------------------------------------------------------------------------ // @函数功能 寻找V点 // @函数返回 V点 //------------------------------------------------------------------------------------------------------------------ //左边V点 uint8 find_point_V_l(void) { uint16 j = border_to_edge_l[target_h];//映射 int16 search_min = j - search_range;//遍历点的最小编号 int16 search_max = j + search_range;//遍历点的最大编号 //限定查找区间 if(search_min < 3) { search_min = 3; } if(search_max > data_stastics_l - 2) { search_max = data_stastics_l - 2; } //遍历寻找V点 for(j = search_min;j <= search_max;j++) { if(points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1]) { V_edge = j; return 1;//找到V点 } } return 0;//未找到V点 } //右边V点 uint8 find_point_V_r(void) { uint16 j = border_to_edge_r[target_h];//映射 int16 search_min = j - search_range;//遍历点的最小编号 int16 search_max = j + search_range;//遍历点的最大编号 //限定查找区间 if(search_min < 3) { search_min = 3; } if(search_max > data_stastics_r - 2) { search_max = data_stastics_r - 2; } //遍历寻找V点 for(j = search_min;j <= search_max;j++) { if(points_l[j+2][1]<points_l[j][1] && points_l[j-2][1] < points_l[j][1]) { V_edge = j; return 1;//找到V点 } } return 0;//未找到V点 } //------------------------------------------------------------------------------------------------------------------ // @函数功能 补线 // @参数说明 m补线下方点,n补线上方点,border需要补线的边线数组,end_point需要补到的高度 // @函数返回 无 //------------------------------------------------------------------------------------------------------------------ void patching_line(uint8 m,uint8 n,uint8 *border,uint8 end_point) { float k = (float)( (m - n) / (border[n] - border[m]) ); for(uint8 h = m - 1;h > end_point;h--) { border[h] = (uint8)(border[m] + (m - h) / k); } } //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // @函数功能 总环岛识别处理函数 // @函数返回 无 //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void island_handler(void) { switch(current_state) { case NORMAL: //判断初见环岛条件 if(border_continuous(r_border) && !border_continuous(l_border) && find_point_A_l() && find_point_P_l())//判断是否为左环岛 { current_state = SEE_ISLAND; island_type = 1;//左环岛 } if(!border_continuous(r_border) && border_continuous(l_border) && find_point_A_r() && find_point_P_r())//判断是否为右环岛 { current_state = SEE_ISLAND; island_type = 2;//右环岛 } break; case SEE_ISLAND://初见环岛 if(island_type == 1)//左环岛 { //找A,P点 border_continuous(l_border); find_point_A_l(); find_point_P_l(); //补线 A_point = points_l[A_edge][1]; l_border[A_point] = points_l[A_edge][0]; patching_line(A_point,P_point,l_border,P_point); //判断初入环岛条件 if(l_border[MT9V03X_H-1] == border_min && l_border[MT9V03X_H-2] == border_min) { current_state = ENTER_ISLAND; } } if(island_type == 2)//右环岛 { //找A,P点 border_continuous(r_border); find_point_A_r(); find_point_P_r(); //补线 A_point = points_r[A_edge][1]; r_border[A_point] = points_r[A_edge][0]; patching_line(A_point,P_point,r_border,P_point); //判断初入环岛条件 if(r_border[MT9V03X_H-1] == border_max && r_border[MT9V03X_H-2] == border_max) { current_state = ENTER_ISLAND; } } break; case ENTER_ISLAND://初入环岛 if(island_type == 1)//左环岛 { //找P点 find_point_P_l(); //补线 A_point = MT9V03X_H-1; patching_line(A_point,P_point,l_border,P_point); //判断第一次到环岛出口条件 if(!border_continuous(l_border) && border_continuous(r_border) && find_point_V_l()) { current_state = EXIT_ISLAND1; } } if(island_type == 2)//右环岛 { //找P点 find_point_P_r(); //补线 A_point = MT9V03X_H-1; patching_line(A_point,P_point,r_border,P_point); //判断第一次到环岛出口条件 if(border_continuous(l_border) && !border_continuous(r_border) && find_point_V_r()) { current_state = EXIT_ISLAND1; } } break; case EXIT_ISLAND1://第一次到环岛出口 if(island_type == 1)//左环岛 { //找V点 border_continuous(l_border); find_point_V_l(); //补线 V_point = points_l[V_edge][1]; r_border[V_point] = points_l[A_edge][0]; patching_line(119,V_point,r_border,0); //判断即将入环条件 if(!border_continuous(r_border) && find_point_V_r()) { current_state = IN_ISLAND; } } if(island_type == 2)//右环岛 { //找V点 border_continuous(r_border); find_point_V_r(); //补线 V_point = points_r[V_edge][1]; l_border[V_point] = points_r[A_edge][0]; patching_line(119,V_point,l_border,0); //判断即将入环条件 if(!border_continuous(l_border) && find_point_V_l()) { current_state = IN_ISLAND; } } break; case PRE_ENTER://即将入环 if(island_type == 1)//左环岛 { //找V点 border_continuous(r_border); find_point_V_r(); //补线 V_point = points_r[V_edge][1]; r_border[V_point] = points_r[A_edge][0]; patching_line(119,V_point,r_border,0); //判断完全入环条件 if(border_continuous(r_border) && border_continuous(l_border)) { current_state = IN_ISLAND; } } if(island_type == 2)//右环岛 { //找V点 border_continuous(l_border); find_point_V_l(); //补线 V_point = points_l[V_edge][1]; l_border[V_point] = points_l[A_edge][0]; patching_line(119,V_point,l_border,0); //判断完全入环条件 if(border_continuous(r_border) && border_continuous(l_border)) { current_state = IN_ISLAND; } } break; case IN_ISLAND://完全入环 if(island_type == 1)//左环岛 { //条件补线 if(!border_continuous(r_border) && border_continuous(l_border)) { r_border[0] = border_min; patching_line(target_h,0,r_border,0); } //判断第二次到环岛出口条件 if( l_border[MT9V03X_H-1]>border_min && l_border[MT9V03X_H-2]>border_min && r_border[MT9V03X_H-1]==border_max && r_border[MT9V03X_H-1]==border_max) { current_state = EXIT_ISLAND2; } } if(island_type == 2)//右环岛 { //条件补线 if(!border_continuous(l_border) && border_continuous(r_border)) { l_border[0] = border_max; patching_line(target_h,0,l_border,0); } //判断第二次到环岛出口条件 if( l_border[MT9V03X_H-1]==border_min && l_border[MT9V03X_H-2]==border_min && r_border[MT9V03X_H-1]<border_max && r_border[MT9V03X_H-1]<border_max) { current_state = EXIT_ISLAND2; } } break; case EXIT_ISLAND2://第二次到环岛出口 if(island_type == 1)//左环岛 { //判断最终出环条件 if(!border_continuous(l_border) && border_continuous(r_border)) { current_state = FINAL_EXIT; } } if(island_type == 2)//右环岛 { //判断最终出环条件 if(border_continuous(l_border) && !border_continuous(r_border)) { current_state = FINAL_EXIT; } } break; case FINAL_EXIT://最终出环 if(island_type == 1)//左环岛 { //补线 border_continuous(l_border); patching_line(119,target_h,l_border,target_h); //结束条件 if(border_continuous(l_border) && border_continuous(r_border)) { current_state = NORMAL; island_type = 0; } } if(island_type == 2)//右环岛 { //补线 border_continuous(r_border); patching_line(119,target_h,r_border,target_h); //结束条件 if(border_continuous(l_border) && border_continuous(r_border)) { current_state = NORMAL; island_type = 0; } } break; } } //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // @函数功能 获取车身偏差 // @函数返回 车身偏差error //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- int16 error = 1000; //误差100 int16 error_last = 0; //上次误差 void car_error(void) { uint8 i = 0; int32 num = 0; //int16 num = 0 for(i = 1;i < MT9V03X_H;i++) { num += (center_line[i] - (MT9V03X_W / 2)); } error_last = error; error = num; } //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // @函数功能 最终处理函数 // @函数返回 无 //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- uint8 change = 0; uint8 change_last = 0; void image_process(void) { uint16 i; uint8 hightest = 0;//定义一个最高行,tip:这里的最高指的是y值的最小 Get_image(mt9v03x_image);//获得一副灰度图像 turn_to_bin();//大津法二值化。 //提取赛道边界 image_filter(bin_image);//滤波减少噪声 image_draw_rectan(bin_image);//给图像画黑框为八领域做准备 //清零 data_stastics_l = 0; data_stastics_r = 0; if (get_start_point(MT9V03X_H - 2))//找到起点了,再执行八领域,没找到就一直找 { navigation_flag = 0; //判断直角弯 uint8 m = 0,n = 0, j = 0; for(j = 1;j < MT9V03X_W;j++) { if(bin_image[60][j] == 255) { break; } if(bin_image[62][j] == 255) { break; } } if(j == MT9V03X_W) { for(j = 119;j > 55;j--) { if(bin_image[j][5] == 255 && bin_image[j][7] == 255) { m = 1; } if(bin_image[j][115] == 255 && bin_image[j][113] == 255) { n = 1; } } } if(m == 1 && n == 0) { navigation_flag = 1; } if(m == 0 && n == 1) { navigation_flag = 2; } //八领域处理 search_l_r((uint16)USE_num, bin_image, &data_stastics_l, &data_stastics_r, start_point_l[0], start_point_l[1], start_point_r[0], start_point_r[1], &hightest); // 从爬取的边界线内提取边线 , 这个才是最终有用的边线 get_left(data_stastics_l); get_right(data_stastics_r); //处理函数 island_handler();//环岛元素识别处理 } else { navigation_flag = 3; } for (i = hightest; i < MT9V03X_H-1; i++) { center_line[i] = (l_border[i] + r_border[i]) >> 1;//求中线 } if(bin_image[118][8] == 0 && bin_image[118][40] == 255 && bin_image[118][100] == 255 && bin_image[118][148] == 255 && bin_image[118][180] == 0 && bin_image[118][94] == 255) { change_last = change; change = 1; } else { change = 0; } if(change == 1 && change_last == 0) { stop++; } 以上代码如何调整参数来降低曝光问题
最新发布
05-28
<think>好的,我需要帮助用户解决如何通过修改代码参数来调整图像曝光的问题,特别是在二值化阈值计算部分。首先,我得回忆一下用户提到的引用内容,看看有没有相关的信息可以利用。用户引用了对数变换的内容,这通常用于增强暗部细节,可能曝光不足有关。引用中提到对数变换可以扩展低灰度区域,压缩高灰度区域,这可能对调整曝光有用。另外,边缘检测部分提到使用CannySobel算子,但用户的问题是关于曝光调整,所以可能需要重点参考对数变换或其他曝光相关的处理方法。 接下来,用户的问题是关于代码参数的调整,特别是二值化阈值计算。我需要考虑常见的曝光问题,比如过度曝光(图像太亮)或曝光不足(图像太暗),以及如何在代码中调整参数来解决这些问题。首先,二值化的阈值选择是关键。如果阈值设置不当,可能导致图像过分割或欠分割。例如,在曝光过度的情况下,图像整体较亮,可能需要提高阈值,将更多的像素归为背景。相反,曝光不足时,可能需要降低阈值,保留更多细节。然后,可能需要使用自适应阈值处理,因为全局阈值可能不适用于光照不均的情况。自适应阈值根据局部区域的像素值计算阈值,可以更好地处理不同区域的曝光问题。 此外,直方图均衡化也是一种常用的方法,可以调整图像的对比度,改善曝光问题。不过用户特别提到了二值化阈值计算,所以可能需要更直接的方法。对数变换伽马校正属于对比度调整的方法,可以扩展暗部或亮部的细节。例如,伽马校正通过调整伽马值来改变图像的亮度分布,伽马值大于1会使图像变暗,适合过度曝光;小于1会使图像变亮,适合曝光不足。现在需要将这些方法转化为具体的代码参数调整。例如,在OpenCV中,二值化的阈值可以通过cv2.threshold()函数调整,自适应阈值使用cv2.adaptiveThreshold(),伽马校正需要先构建查找表,再应用LUT函数。 可能需要分步骤说明如何调整这些参数,比如:1.调整全局阈值:选择合适的阈值,或使用大津法自动确定。2.改用自适应阈值:选择块大小常数C。3.应用伽马校正:调整伽马值。 4.结合直方图均衡化:特别是对比度受限的CLAHE方法。 还需要考虑不同情况下的参数建议,比如曝光过度时降低伽马值,曝光不足时提高伽马值。同时,要提醒用户进行实验,逐步调整参数,并使用直方图分析工具辅助。最后,生成相关问题,可能涉及其他曝光调整技术、参数自动确定方法、多方法结合的效果,以及处理后的图像评估方法等。</think>### 图像曝光调整的参数优化方法 曝光问题通常源于图像亮度分布失衡,可通过以下代码参数调整解决: --- #### 1. **二值化阈值调整** 在固定阈值法中,直接修改阈值参数可控制像素分类: ```python import cv2 _, binary_img = cv2.threshold(img, thresh=120, maxval=255, type=cv2.THRESH_BINARY) ``` - **曝光过度**(整体偏亮):提高`thresh`值(如160),过滤更多高光区域[^1]。 - **曝光不足**(整体偏暗):降低`thresh`值(如80),保留更多暗部细节。 **优化建议**:改用大津法(`cv2.THRESH_OTSU`)自动计算最佳阈值。 --- #### 2. **自适应阈值优化** 当光照不均时,使用自适应阈值代替全局阈值: ```python adaptive_img = cv2.adaptiveThreshold( img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize=11, C=2 ) ``` - **`blockSize`**:控制局部区域大小,奇数(建议11-31)。值越大,对光照变化越敏感。 - **`C`**:微调阈值偏移量。曝光过度时增大`C`,曝光不足时减小`C`。 --- #### 3. **伽马校正** 通过非线性变换调整亮度分布,公式为: $$ O = I^{\gamma} $$ ```python gamma = 0.5 # 曝光过度时γ<1,不足时γ>1 lookup_table = np.array([(i / 255) ** gamma * 255 for i in range(256)], dtype=np.uint8) gamma_img = cv2.LUT(img, lookup_table) ``` --- #### 4. **直方图均衡化** 扩展动态范围以平衡曝光: ```python # 全局均衡化 equalized_img = cv2.equalizeHist(img) # 局部均衡化(CLAHE) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) clahe_img = clahe.apply(img) ``` - **`clipLimit`**:限制对比度增强幅度(建议2-3)。 - **`tileGridSize`**:分块数量,影响局部细节保留能力[^2]。 --- ### 参数调整建议 | 问题类型 | 推荐方法 | 关键参数示例 | |----------------|------------------------|-----------------------| | 全局曝光过度 | 伽马校正 + 提高二值化阈值 | γ=0.7, thresh=180 | | 局部高光过曝 | CLAHE + 自适应阈值 | clipLimit=3, blockSize=15 | | 低对比度暗光 | 对数变换 + 大津法阈值 | c=40, 自动计算阈值 | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值