p21 p22初始指针(1)(2)

本章重点

1.指针是什么?

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单位,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

指针是个变量,存放内存单元的地址(编号)。

那对应的代码:

int main()
{
    int a=10;        //在内存中开辟一块空间
    int *p=&a;//指针变量        //这里我们对变量a,取出它的地址,可以使用&操作符

//将a的地址存放在p变量中,p就是一个指针变量。

    return 0;
}

//总结:指针就变量,用来哦存放地址的变量。(存放在指针中的值都被当成地址处理)。

那这里的问题是:

一个小的单元到底是多大?(1个字节)

如何编址?

经过仔细地集散和权衡我们发现一个字节给一个对应的地址是比较合适的。

对于32位的机器,假设有32根地址线,那么假设没跟地址线在寻址的是产生一个电信号正点/负电(1或者0)

那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000

....

11111111 11111111 11111111 11111111

这里是2的32次方个地址

每个地址标识一个字节,那我们就可以给(2^32Byte==2^32/1024kB==2^32/1024/1024MB==2^32/1024/1024/1024GB==4GB)4G的空闲进行编址。

同样的方法,那64位机器,如果给64根地址线,哪能编制多大的空间呢?自己计算

这里我们明白:

在32位机器上,地址是32个0或者1组成二进制序列,那地址就得用4鸽子姐的空间来存储,所以一个指针变量的大小就应该是4个字节。

那如果在64位机器上,如果64个地址线,那一个指针变量的大小事8鸽子姐,才能存放一个地址。

总结:

  • 指针式用来存放地址的,地址是唯一标识一块地址空间的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。

2.指针和指针的类型

这里我们讨论一下:指针的类型我们知道,变量有不同的类型,整型,浮点型等。那只真有没有类型呢?准确的说:有的。

int main(){
	printf("%d\n",sizeof(char*));
	printf("%d\n",sizeof(short*));
	printf("%d\n",sizeof(int*));
	printf("%d\n",sizeof(double*));
	return 0;
}

结果是4 4 4 4 

int a=0x11223344;
    int *pa=&a;
    char *pc=&a;
    printf("%p\n",pa);
    printf("%p\n",pc);

int a=0x11223344;

char *pc=&a;

*pc=0;

指针类型决定了指针进行解引用操作的时候,能够访问空间的大小。

int *p; *p能够访问4个字节

char *p;*p能够访问1个字节

double *p;*p能够访问8个字节

int main(){
//	printf("%d\n",sizeof(char*));
//	printf("%d\n",sizeof(short*));
//	printf("%d\n",sizeof(int*));
//	printf("%d\n",sizeof(double*));
	int a=0x11223344;
	int *pa=&a;
	char*pc =&a;


//	char *pc=&a;
	printf("%p\n",pa);
	printf("%p\n",pa+1);
	printf("%p\n",pc);
	printf("%p\n",pc+1);
	return 0;
}

 

指针类型决定了:指针走一步走多远(指针的步长)

int *p;p+1-->4

char *p;p+1-->1

double *p;p+1-->8;

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

int main(){
    int arr[10]={0};
    int *p=arr;//数组名-首元素的地址
    int i=0;
    for(i=0;i<10;i++)
    {
        *(p+i)=1;
    }
    return 0;
}

总结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节),比如:char *的指针解引用就只能访问一个自己而,而int *的指针的解引用就能访问四个字节。

3.野指针

概念:野指针就是指针指向的位置是不可知的(随机的,不正确的没有明确限制的)

野指针成因

1.指针未初始化

int main(){
    int *p;//局部的指针变量,就被初始化随机值
    *p=20;//局部的指针变量,就被初始化随机值


    return 0;
}

2.指针越界访问

int main(){
    int arr[10]={0};
    int *p=arr;
    int i=0;
    for(i=0;i<12;i++)
    {
        //当指针指向的范围超出数组arr的范围时,p就是野指针

        //*(p++)=i;

*p=i;

p++;

    }
    return 0;
}

如何规避指针

1.指针初始化

2.小心指针越界

3.指针指向空间释放及时置为NULL

4.指针使用之前检查有效性

int *test()
{
	int a=10;
	return &a;
}
int main()
{
	int *p=test();
	printf("%d\n",*p);
	return 0;
}

int *test()
{
//    int a=10;
//    return &a;
    int arr[10]={0};
    return arr;
}
int main()
{
    int *p=test();
    printf("%d\n",*p);
    return 0;
}

int main(){
    int b=0;
    int a=10;
    int *pa=&a;//初始化
    int *p=NULL;//NULL-用来初始化指针的,给指针变量初始化

}

int main(){
int a=10;
int*pa=&a;
*pa=20;
pa=NULL;

if(pa!=NULL){

}
return 0;
}

4.指针运算

  • 指针+-整数
  • 指针-指针
  • 指针的关系运算

指针+-整数

#define N_VALUES 5

float value[N_VALUES];

float *vp;

//指针+-整数;指针的关系运算

for(vp=&values[0];vp<&values[N_VALUES];)

{

        *vp++=0;

}

int main(){
	int arr[10]={1,2,3,4,5,6,7,8,9,10};
	int i=0;
	int sz=sizeof(arr)/sizeof(arr[0]);
	int *p=arr;
	for(i=0;i<10;i++){
		printf("%d ",*p);
		p++;
	}
	return 0;
}

p+2;

跳两个地址

1 3 5 7 9 

int main(){
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int i=0;
    int *p=&arr[9];
    for(i=0;i<5;i++){
        printf("%d ",*p);
        p-=2;;
    }
    return 0;
}
 

地址减地址

int main(){
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    printf("%d\n",&arr[9]-&arr[0]);

    return 0;
}

结果是9

int my_strlen(char *str)
{
	char *start=str;
	char*end=str;
	while(*end!='\0')
	{
		end++;
	}
	return end-start;
}
int main(){
	//strlen -求字符串长度
	//递归 -模拟实现了strlen -计数器的方式1,递归方式2
	//
	char arr[]="bit";

	int len=my_strlen(arr);
	printf("%d\n",len);
	return 0;
}

 指针比较大小

#define N_VALUES 5

flaot values[N_VALUES]

float *vp;

for(vp =&values[N_VALUES];vp>&values[0];){

*--vp=0;

}

for(vp =&values[N_VALUES-1];vp>=&values[0];vp--){

*vp=0;

}

实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存存在位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

5.指针和数组

 int main()
{
    int arr[10]={0};
    printf("%p\n",arr);//地址-首元素地址
    printf("%p\n",&arr[0]);
    printf("%p\n",&arr);
    //1.&arr-&数组名-数组名不是首元素地址-数组名表示整个数组-&数组名-取出的是整个数组的地址
    //2.sizeof(arr)-sizeof(数组名)-数组名表示的是整个数组-sizeof(数组名)计算的是整个数组名的大小

    return 0;
}

 

int main()
{
	int arr[10]={0};
	printf("%p\n",arr);//地址-首元素地址
	printf("%p\n",arr+1);//地址-首元素地址
	printf("%p\n",&arr[0]);
	printf("%p\n",&arr[0]+1);
	printf("%p\n",&arr);
	printf("%p\n",&arr+1);
	//1.&arr-&数组名-数组名不是首元素地址-数组名表示整个数组-&数组名-取出的是整个数组的地址
	//2.sizeof(arr)-sizeof(数组名)-数组名表示的是整个数组-sizeof(数组名)计算的是整个数组名的大小

	return 0;
}

int main(){
	int arr[10]={0};
	int *p=arr;
	int i=0;
	for(i=0;i<10;i++){
		printf("%p ======  %p\n",p+i,&arr[i]);
	}
	return 0;
}

写法一:

int main(){
    int arr[10]={0};
    int *p=arr;
    int i=0;
    for(i=0;i<10;i++)
    {
        *(p+i)=i;
    }
    for(i=0;i<10;i++)
    {
        printf("%d\n",*(p+i));
    }

写法二:

int main(){
    int arr[10]={0};
    int *p=arr;
    int i=0;
    for(i=0;i<10;i++)
    {
        *(p+i)=i;
    }
    for(i=0;i<10;i++)
    {
        printf("%d\n",arr[i]);
    }

6.二级指针

int main(){
    int a=10;
    int *pa=&a;
    int **ppa=&pa;//二级指针
    //int ***pppa=&ppa;//三级指针
    printf("%d\n",**ppa);
    return 0;
}

int main(){
    int a=10;
    int *pa=&a;
    int **ppa=&pa;//二级指针
    //int ***pppa=20;//三级指针
    printf("%d\n",**ppa);

    printf("%d\n",a);
    return 0;
}

结果都是20

7.指针数组

好孩子--孩子

指针数组---数组--存放指针的数组

//数组指针--指针

int main()

{

        int a=10;

        int b=20;

        int c=30;

      //  int*pa=&a;

        //int *pb=&b;

        //int *pc=&c;

//整形数组-存放整型

//字符数组-存放字符

//指针数组-存放指针

//int arr[10];

int*arr2[3]={&a,&b,&c};//指针数组

int i=0;

for(i=0;i<3;i++){

printf("%d\n",*(arr2[i]));

}

        return 0;

}

 

下面是我要进行的抗阳光操作:局部伽马矫正 → 对数域梯度提取 → 改进Sobel边缘检测 → 局部动态窗口阈值分割 → 请你帮我优化一下,最好有注释 // 在结构体中添加需要的字段 typedef struct { _Bool FINISH; uint8 IMAGE[IMAGE_AH][IMAGE_AW]; // 原始图像 uint8 UNDST[IMAGE_AH][IMAGE_AW]; // 去畸变图像 uint8 GAMMA[IMAGE_AH][IMAGE_AW]; // 伽马变换图像 uint8 GRADIENT[IMAGE_AH][IMAGE_AW]; // 梯度图像(新增) uint8 BIN[IMAGE_AH][IMAGE_AW]; // 二值化图像 uint8 BIN_FILTER[IMAGE_AH][IMAGE_AW]; // 二值化去噪点图像 uint8 threshold; // 基础阈值 uint8 GREY_OFFSET; // 阈值增幅 uint8 dynamic_w; // 动态窗口宽度参数(新增) uint8 lost_count; // 路径丢失计数(新增) } MT9V034A_t; // 改进Sobel算子模板(4个方向) static const int8_t sobel_templates[4][3][3] = { // 0° 模板 {{-1, -3, -1}, { 0, 0, 0}, { 1, 3, 1}}, // 45° 模板 {{-1, 0, 1}, {-3, 0, 3}, {-1, 0, 1}}, // 90° 模板 {{-1, -3, -1}, { 0, 0, 0}, { 1, 3, 1}}, // 135° 模板 {{ 0, -1, -2}, { 1, 0, -1}, { 2, 1, 0}} }; /** * @brief 局部伽马矫正(基于图像平均亮度) * @param cam 摄像头数据结构指针 * @param input_source 输入源选择 (0:原始图像, 1:去畸变图像) */ void LocalGammaCorrection(MT9V034A_t *cam, uint8_t input_source) { // 确定输入图像 uint8 (*input_image)[IMAGE_AW] = (input_source == 0) ? cam->IMAGE : cam->UNDST; uint8 (*output_image)[IMAGE_AW] = cam->GAMMA; // 计算图像平均灰度 uint32_t sum = 0; for (int y = 0; y < IMAGE_AH; y++) { for (int x = 0; x < IMAGE_AW; x++) { sum += input_image[y][x]; } } float f_p = (float)sum / (IMAGE_AH * IMAGE_AW); // 为每个像素计算并应用伽马值 for (int y = 0; y < IMAGE_AH; y++) { for (int x = 0; x < IMAGE_AW; x++) { uint8_t pixel = input_image[y][x]; float gamma_val; // 根据像素值选择伽马系数 if (pixel <= f_p / 2) { gamma_val = 0.45f; } else if (pixel <= 7 * f_p / 8) { gamma_val = 0.67f; } else if (pixel <= 9 * f_p / 8) { gamma_val = 1.00f; } else if (pixel <= 3 * f_p / 2) { gamma_val = 1.50f; } else { gamma_val = 2.50f; } // 应用伽马矫正 float normalized = pixel / 255.0f; float corrected = powf(normalized, gamma_val); output_image[y][x] = (uint8_t)(corrected * 255.0f + 0.5f); } } } /** * @brief 计算对数域梯度(光照不变特征) * @param cam 摄像头数据结构指针 */ void ComputeLogGradient(MT9V034A_t *cam) { // 使用伽马矫正后的图像 uint8 (*input_image)[IMAGE_AW] = cam->GAMMA; uint8 (*grad_image)[IMAGE_AW] = cam->GRADIENT; for (int y = 1; y < IMAGE_AH - 1; y++) { for (int x = 1; x < IMAGE_AW - 1; x++) { // 获取3x3邻域 float p11 = input_image[y-1][x-1] + 1; // +1避免log(0) float p12 = input_image[y-1][x] + 1; float p13 = input_image[y-1][x+1] + 1; float p21 = input_image[y][x-1] + 1; float p22 = input_image[y][x] + 1; float p23 = input_image[y][x+1] + 1; float p31 = input_image[y+1][x-1] + 1; float p32 = input_image[y+1][x] + 1; float p33 = input_image[y+1][x+1] + 1; // 转换到对数域 float l11 = logf(p11); float l12 = logf(p12); float l13 = logf(p13); float l21 = logf(p21); float l22 = logf(p22); float l23 = logf(p23); float l31 = logf(p31); float l32 = logf(p32); float l33 = logf(p33); // 计算四个方向的梯度(使用改进Sobel模板) float gradients[4] = {0}; // 0° 方向 gradients[0] = fabsf( (-1)*l11 + (-3)*l12 + (-1)*l13 + ( 0)*l21 + ( 0)*l22 + ( 0)*l23 + ( 1)*l31 + ( 3)*l32 + ( 1)*l33); // 45° 方向 gradients[1] = fabsf( (-1)*l11 + ( 0)*l12 + ( 1)*l13 + (-3)*l21 + ( 0)*l22 + ( 3)*l23 + (-1)*l31 + ( 0)*l32 + ( 1)*l33); // 90° 方向 gradients[2] = fabsf( (-1)*l11 + ( 0)*l12 + ( 1)*l13 + (-3)*l21 + ( 0)*l22 + ( 3)*l23 + (-1)*l31 + ( 0)*l32 + ( 1)*l33); // 135° 方向 gradients[3] = fabsf( ( 0)*l11 + (-1)*l12 + (-2)*l13 + ( 1)*l21 + ( 0)*l22 + (-1)*l23 + ( 2)*l31 + ( 1)*l32 + ( 0)*l33); // 取无穷范数(最大梯度值) float max_grad = 0; for (int i = 0; i < 4; i++) { if (gradients[i] > max_grad) { max_grad = gradients[i]; } } // 归一化并存储梯度 grad_image[y][x] = (uint8_t)fminf(255, max_grad * 30); // 缩放因子 } } // 边界处理 for (int y = 0; y < IMAGE_AH; y++) { grad_image[y][0] = 0; grad_image[y][IMAGE_AW-1] = 0; } for (int x = 0; x < IMAGE_AW; x++) { grad_image[0][x] = 0; grad_image[IMAGE_AH-1][x] = 0; } } /** * @brief 局部动态窗口阈值处理 * @param cam 摄像头数据结构指针 */ void LocalDynamicThreshold(MT9V034A_t *cam) { uint8 (*grad_image)[IMAGE_AW] = cam->GRADIENT; uint8 (*bin_image)[IMAGE_AW] = cam->BIN; // 初始化动态窗口大小 if (cam->dynamic_w == 0) { cam->dynamic_w = 2; // 默认窗口大小 } int w = cam->dynamic_w; int window_size = 2 * w + 1; for (int y = w; y < IMAGE_AH - w; y++) { for (int x = w; x < IMAGE_AW - w; x++) { // 统计窗口内像素 uint16_t sum = 0; uint8_t min_val = 255; uint8_t max_val = 0; for (int i = -w; i <= w; i++) { for (int j = -w; j <= w; j++) { uint8_t val = grad_image[y+i][x+j]; sum += val; if (val < min_val) min_val = val; if (val > max_val) max_val = val; } } // 计算动态阈值(排除最大最小值) uint8_t threshold = (sum - min_val - max_val) / (window_size * window_size - 2); // 应用阈值 bin_image[y][x] = (grad_image[y][x] > threshold) ? 1 : 0; } } // 路径丢失检测逻辑 int path_pixels = 0; for (int y = IMAGE_AH/2; y < IMAGE_AH; y++) { for (int x = 0; x < IMAGE_AW; x++) { if (bin_image[y][x]) path_pixels++; } } if (path_pixels < 20) { cam->lost_count++; if (cam->lost_count > 5) { cam->dynamic_w = 3; // 增大窗口减少细节敏感度 } } else { cam->lost_count = 0; cam->dynamic_w = 2; // 恢复正常窗口大小 } } /** * @brief 抗阳光干扰路径识别主函数 * @param cam 摄像头数据结构指针 */ void AntiSunlightPathRecognition(MT9V034A_t *cam) { // 1. 局部伽马矫正(使用原始图像) LocalGammaCorrection(cam, 0); // 2. 计算对数域梯度 ComputeLogGradient(cam); // 3. 局部动态阈值处理 LocalDynamicThreshold(cam); // 4. 可选:二值图像滤波 Image_Bin_Filter(cam); }
06-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

靳向阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值