MultProc.c
9.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/***************
*
* 多媒体处理器
* Multimedia Processor
*
* ******************/
#include "stdio.h"
#include "./MultProc.h"
#include "JZsdkLib.h"
// 将RGB888格式转换为YUV420P格(I420)
T_JZsdkReturnCode Stream_rgb888_to_yuv420p(U8_t *rgb_data, int width, int height, U8_t *yuv_data)
{
// YUV420P格式的大小:Y平面后面跟着U和V平面,它们的高度和宽度都是原图像的一半
int y_size = width * height;
int u_size = (width / 2) * (height / 2) ; // U和V平面交错存储
// YUV420P的各个平面
U8_t *y_plane = yuv_data;
U8_t *u_plane = yuv_data + y_size;
U8_t *v_plane = u_plane + u_size;
// RGB888到YUV420P的转换
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
// 计算Y分量的索引
int y_idx = j * width + i;
// 计算UV分量的索引(每个第二个像素存储一次)
int uv_idx = (j / 2) * (width / 2) + (i / 2);
// 提取RGB分量
U8_t r = rgb_data[y_idx * 3];
U8_t g = rgb_data[y_idx * 3 + 1];
U8_t b = rgb_data[y_idx * 3 + 2];
// 将RGB转换为YUV
int y = ((66 * r + 129 * g + 25 * b + 128) >> 8);
int u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
int v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
// 存储Y分量
y_plane[y_idx] = (U8_t)y;
// 仅当为每第二个像素时存储U和V分量
if ((i & 1) == 0 && (j & 1) == 0)
{
u_plane[uv_idx] = (U8_t)u;
v_plane[uv_idx] = (U8_t)v;
}
}
}
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
//rgb888 转yuv420sp MPP_FMT_YUV420SP = (MPP_FRAME_FMT_YUV + 0), /* YYYY... UV... (NV12) */
T_JZsdkReturnCode Stream_rgb888_to_yuv420sp(U8_t *rgb_data, int width, int height, U8_t *yuv_data)
{
// YUV420SP(NV12)格式的大小:Y平面后面跟着一个交织的UV平面
int y_size = width * height;
int uv_size = (width / 2) * (height / 2) * 2; // UV平面交织存储,所以大小是U或V平面的两倍
// YUV420SP的各个平面
U8_t *y_plane = yuv_data;
U8_t *uv_plane = yuv_data + y_size;
// RGB888到YUV420SP的转换
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
// 计算Y分量的索引
int y_idx = j * width + i;
// 计算UV分量的索引(每个第二个像素存储一次)
int uv_idx = (j / 2) * (width / 2) + (i / 2);
// 提取RGB分量
U8_t r = rgb_data[y_idx * 3];
U8_t g = rgb_data[y_idx * 3 + 1];
U8_t b = rgb_data[y_idx * 3 + 2];
// 将RGB转换为YUV
int y = ((66 * r + 129 * g + 25 * b + 128) >> 8);
int u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
int v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
// 存储Y分量
y_plane[y_idx] = (U8_t)y;
// 仅当为每第二个像素时存储U和V分量
if ((i & 1) == 0 && (j & 1) == 0)
{
// 存储U分量
uv_plane[uv_idx * 2] = (U8_t)u;
// 存储V分量
uv_plane[uv_idx * 2 + 1] = (U8_t)v;
}
}
}
// 注意:如果图像的宽度或高度不是偶数,上面的代码可能无法正确处理最后一行或一列。
// 在实际应用中,通常需要确保图像的尺寸是2的倍数,或者添加适当的边界处理代码。
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
/*************************
*
* /rgb888图片画框
* 暂时不加入宽度功能
*
* *************************/
T_JZsdkReturnCode Stream_rgb888_WriteRectangle(U8_t *rgb_data, int width, int height, int Point1_X, int Point1_Y, int Point2_X, int Point2_Y, int R_Color,int G_Color, int B_Color, int DrawWidth)
{
//涂色
//找到矩形的左上角
int LeftTop_X = JZ_MATH_MIN(Point1_X, Point2_X);
int LeftTop_Y = JZ_MATH_MIN(Point1_Y, Point2_Y);
//找到矩形的左下角
int LeftDown_X = JZ_MATH_MAX(Point1_X, Point2_X);
int LeftDown_Y = JZ_MATH_MAX(Point1_Y, Point2_Y);
//找到矩形的右上角
int RightTop_X = JZ_MATH_MIN(Point1_X, Point2_X);
int RightTop_Y = JZ_MATH_MIN(Point1_Y, Point2_Y);
//找到矩形的右下角
int RightDown_X = JZ_MATH_MAX(Point1_X, Point2_X);
int RightDown_Y = JZ_MATH_MAX(Point1_Y, Point2_Y);
// 确保坐标在有效范围内
if (LeftTop_X < 0) LeftTop_X = 0;
if (LeftTop_Y < 0) LeftTop_Y = 0;
if (RightDown_X >= width) RightDown_X = width - 1;
if (RightDown_Y >= height) RightDown_Y = height - 1;
// 计算起始位置(以字节为单位,每个像素3字节)
//int start_base = LeftTop_Y * width * 3 + LeftTop_X * 3;
// // 填充矩形区域
// for (int y = LeftTop_Y; y <= RightDown_Y; y++) {
// for (int x = LeftTop_X; x <= RightDown_X; x++) {
// int offset = (y * width + x) * 3;
// rgb_data[offset] = R_Color; // R
// rgb_data[offset + 1] = G_Color; // G
// rgb_data[offset + 2] = B_Color; // B
// }
// }
// 确保DrawWidth在有效范围内
if (DrawWidth < 1) DrawWidth = 1;
if (DrawWidth > (RightDown_X - LeftTop_X + 1) / 2) DrawWidth = (RightDown_X - LeftTop_X + 1) / 2; // 防止宽度过大导致超出矩形
if (DrawWidth > (RightDown_Y - LeftTop_Y + 1) / 2) DrawWidth = (RightDown_Y - LeftTop_Y + 1) / 2;
// 绘制矩形边框
// 上边
for (int x = LeftTop_X; x <= RightDown_X; x++) {
for (int dw = 0; dw < DrawWidth; dw++) {
int offset = ((LeftTop_Y - dw) * width + x) * 3;
if (offset >= 0 && offset < width * height * 3) { // 检查边界
rgb_data[offset] = R_Color;
rgb_data[offset + 1] = G_Color;
rgb_data[offset + 2] = B_Color;
}
}
}
// 下边
for (int x = LeftTop_X; x <= RightDown_X; x++) {
for (int dw = 0; dw < DrawWidth; dw++) {
int offset = ((RightDown_Y + dw) * width + x) * 3;
if (offset >= 0 && offset < width * height * 3) { // 检查边界
rgb_data[offset] = R_Color;
rgb_data[offset + 1] = G_Color;
rgb_data[offset + 2] = B_Color;
}
}
}
// 左边
for (int y = LeftTop_Y; y <= RightDown_Y; y++) {
for (int dw = 0; dw < DrawWidth; dw++) {
int offset = (y * width + (LeftTop_X - dw)) * 3;
if (offset >= 0 && offset < width * height * 3) { // 检查边界
rgb_data[offset] = R_Color;
rgb_data[offset + 1] = G_Color;
rgb_data[offset + 2] = B_Color;
}
}
}
// 右边
for (int y = LeftTop_Y; y <= RightDown_Y; y++) {
for (int dw = 0; dw < DrawWidth; dw++) {
int offset = (y * width + (RightDown_X + dw)) * 3;
if (offset >= 0 && offset < width * height * 3) { // 检查边界
rgb_data[offset] = R_Color;
rgb_data[offset + 1] = G_Color;
rgb_data[offset + 2] = B_Color;
}
}
}
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
/*************************
*
* rgb888 画十字
*
* *************************/
T_JZsdkReturnCode Stream_rgb888_WriteCross(U8_t *rgb_data, int width, int height, int PointX, int PointY, int R_Color,int G_Color, int B_Color, int DrawWidth, int DrawHeight)
{
// 确保DrawWidth和DrawHeight为奇数,且不小于1
if (DrawWidth % 2 == 0) DrawWidth--;
if (DrawHeight % 2 == 0) DrawHeight--;
// 排查是否有足够的位置画十字
if (PointX < DrawWidth / 2 || PointX >= (width - DrawWidth / 2) || PointY < DrawHeight / 2 || PointY >= (height - DrawHeight / 2))
{
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
// 中心点
int base = (PointY * width + PointX) * 3;
// 绘制垂直线
for (int dy = -DrawWidth / 2; dy <= DrawWidth / 2; dy++)
{
// 确保不会超出图像范围
int y = PointY + dy;
if (y >= 0 && y < height)
{
int offset = y * width * 3;
rgb_data[offset + PointX * 3] = R_Color;
rgb_data[offset + PointX * 3 + 1] = G_Color;
rgb_data[offset + PointX * 3 + 2] = B_Color;
}
}
// 绘制水平线
for (int dx = -DrawHeight / 2; dx <= DrawHeight / 2; dx++)
{
// 确保不会超出图像范围
int x = PointX + dx;
if (x >= 0 && x < width)
{
int offset = base + dx * 3;
rgb_data[offset] = R_Color;
rgb_data[offset + 1] = G_Color;
rgb_data[offset + 2] = B_Color;
}
}
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}