1. 裁剪NV21或NV12需要注意Y、U、V三者的共用关系,Y的裁剪比较直接;但是对于U和V而言,U和V的大小各只有Y的大小的1/4(U的宽高和V的宽高都是Y的宽高的一半),因此在横纵向都要进行跳行,在横向由于U和V是交叉排序,width / 2 的V和 width / 2 的U加起来刚好就是Y的大小,可以直接按偏移量裁剪。
void cropYuv420sp(char *yuv420sp, char *cropYuv420sp, int width, int height, int left, int top,
int right, int bottom) {
int halfWidth = width / 2;
int cropImageWidth = right - left;
int cropImageHeight = bottom - top;
//复制Y
int originalYLineStart = top * width;
int targetYIndex = 0;
//复制UV
int originalUVLineStart = width * height + top * halfWidth;
int targetUVIndex = cropImageWidth * cropImageHeight;
for (int i = top; i < bottom; i++) {
memcpy(cropYuv420sp + targetYIndex, yuv420sp + originalYLineStart + left, cropImageWidth);
originalYLineStart += width;
targetYIndex += cropImageWidth;
if ((i & 1) == 0) {
memcpy(cropYuv420sp + targetUVIndex, yuv420sp + originalUVLineStart + left,
cropImageWidth);
originalUVLineStart += width;
targetUVIndex += cropImageWidth;
}
}
}
2. 裁剪YV12或I420
和裁剪NV21类似;Y的裁剪比较直接;但是对于U和V而言;U和V的大小各只有Y的大小的1/4;且是各自连续排序;U的宽高和V的宽高都是Y的宽高的一半;因此在横纵向都要进行跳行。
void cropYuv420p(char *yuv420p, char *cropYuv420p, int width, int height, int left, int top,
int right, int bottom) {
int halfWidth = width / 2;
int cropImageWidth = right - left;
int cropImageHeight = bottom - top;
//复制Y
int originalYLineStart = top * width;
int targetYIndex = 0;
//复制UV
int originalULineStart = width * height + top * halfWidth / 2;
int originalVLineStart = width * height + width * height / 4 + top * halfWidth / 2;
int targetUIndex = cropImageWidth * cropImageHeight;
int targetVIndex = cropImageWidth * cropImageHeight * 5 / 4;
int halfImageWidth = halfWidth;
int halfLeft = left / 2;
int halfCropImageWidth = cropImageWidth / 2;
for (int i = top; i < bottom; i++) {
memcpy(cropYuv420p + targetYIndex, yuv420p + originalYLineStart + left, cropImageWidth);
originalYLineStart += width;
targetYIndex += cropImageWidth;
if ((i & 1) == 0) {
memcpy(cropYuv420p + targetUIndex, yuv420p + originalULineStart + halfLeft,
halfCropImageWidth);
memcpy(cropYuv420p + targetVIndex, yuv420p + originalVLineStart + halfLeft,
halfCropImageWidth);
originalULineStart += halfImageWidth;
originalVLineStart += halfImageWidth;
targetUIndex += halfCropImageWidth;
targetVIndex += halfCropImageWidth;
}
}
}
3. 裁剪YUYV
和NV21、I420之类的数据不同;YUYV的排列方式是YUYV YUYV....;每行的连续4个byte会有共用关系;这4个byte相当于2个像素;每行的数据宽度是 width * 2。 注意:该函数对入参有限制,需要裁剪的边界都需要是偶数。
void cropYuyv(char *yuyv, char *cropYuyv, int width, int height, int left, int top, int right,
int bottom) {
int cropImageWidth = right - left;
int cropImageHeight = bottom - top;
int lineDataSize = width * 2;
int cropLineDataSize = cropImageWidth * 2;
int originalLineStart = top * width * 2;
int targetIndex = 0;
int lineOffsetDataSize = left * 2;
for (int i = top; i < bottom; i++) {
memcpy(cropYuyv + targetIndex, yuyv + originalLineStart + lineOffsetDataSize, cropLineDataSize);
originalLineStart += lineDataSize;
targetIndex += cropLineDataSize;
}
}
4. 裁剪BGR24
无论是BGR24、RGB24;在裁剪时;都是以3个byte为一个整体进行裁剪;因此以下代码兼容24bpp的RGB数据的裁剪。
void cropRgb24(char *rgb24, char *cropRgb24, int width, int height, int left, int top, int right,
int bottom) {
int cropImageWidth = right - left;
int cropImageHeight = bottom - top;
int lineDataSize = width * 3;
int cropLineDataSize = cropImageWidth * 3;
int originalLineStart = top * lineDataSize;
int targetIndex = 0;
int lineOffsetDataSize = left * 3;
for (int i = top; i < bottom; i++) {
memcpy(cropRgb24 + targetIndex, rgb24 + originalLineStart + lineOffsetDataSize, cropLineDataSize);
originalLineStart += lineDataSize;
targetIndex += cropLineDataSize;
}
}