视音频数据处理入门:颜色空间(一)---转换理解

2023-10-28 18:50

本文主要是介绍视音频数据处理入门:颜色空间(一)---转换理解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、YUV颜色空间

概述 

I420的理解

YV12的理解

NV12的理解

NV21的理解

YV12​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​与I420颜色空间相互转换

转换代码

NV12与I420颜色空间相互转换

转换代码

NV21与YV12颜色空间相互转换

转换代码

二、YUV转RGB

概述 

RGB32的理解

RGB24的理解

I420与RGB32颜色空间相互转换

转换代码

I420与RGB24颜色空间相互转换

转换代码

 三、代码路径


​​​​​​​

一、YUV颜色空间

概述 

 简单说一下I420、YV12、NV12、NV21的颜色空间排列方式,更容易理解它们直接相互方式。对于I420、YV12、NV12、NV21四中格式都属于YUV 4:2:0的的排列方式,我的理解是4个Y分量公用一个U和V分量。

I420的理解

I420(YU12)属于YUV420P又称YUV420plane平面模式;Y、U、V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,且与YV12同属于YUV420P;对于I420的图像上排列方式如图-I420(1),首先是Y分量的排布,排布Y分量的宽为图像的宽(W),Y分量的高为图像的高(H);  其次是U分量的排布,排布U分量的宽为图像的宽的一半(W/2),U分量的高为图像的高(H/2);再次是V分量的排布,排布V分量的宽与U分量一致,分别为图像的宽的一半(W/2)和图像的高(H/2)。Y分量、U分量、V分量依次排列。

Y0Y1Y2Y3Y4Y5Y6Y7
Y8Y9Y10Y11Y12Y13Y14Y15
Y16Y17Y18Y19Y20Y21Y22Y23
Y24Y25Y26Y27Y28Y29Y30Y31
U0U1U2U3U4U5U6U7
V0V1V2V3V4V5V6V7

                                                                   图-I420(1)

 如 图-I420(1)红色部分Y0、Y1、Y8、Y9共用U0和V0分量;依次类推,对应颜色的Y分量共用对应颜色的U和V分量。

i420的内存排列,如图-I420(2),依次是Y分量、U分量、V分量;

其中Y分量内存大小为:

Y分量buff_size = W * H ;

其中U分量内存大小为:

U分量buff_size = W/2 * H/2 ,即W * H /4 ;

其中V分量内存大小为:

V分量buff_size = W/2 * H/2 ,即W * H /4 ;

i420图像大小 = Y分量大小 + U分量大小 +V分量大小

即:

i420图像大小 =W * H *3/2

                                                 图-I420(2)

YV12的理解

YV12属于YUV420P又称YUV420plane平面模式;Y、U、V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,且与(I420)YU12同属于YUV420P;对于YV12的图像上排列方式如图-YV12(1),首先是Y分量的排布,排布Y分量的宽为图像的宽(W),Y分量的高为图像的高(H);  其次是U分量的排布,排布U分量的宽为图像的宽的一半(W/2),U分量的高为图像的高(H/2);再次是V分量的排布,排布V分量的宽与U分量一致,分别为图像的宽的一半(W/2)和图像的高(H/2)。Y分量、U分量、V分量依次排列。

Y0Y1Y2Y3Y4Y5Y6Y7
Y8Y9Y10Y11Y12Y13Y14Y15
Y16Y17Y18Y19Y20Y21Y22Y23
Y24Y25Y26Y27Y28Y29Y30Y31
V0V1V2V3V4V5V6V7
U0U1U2U3U4U5U6U7

                                                               图-YV12(1)

 如 图-YV12(1)红色部分Y0、Y1、Y8、Y9共用U0和V0分量;依次类推,对应颜色的Y分量共用对应颜色的U和V分量。

YV12的内存排列,如图-YV12(2),依次是Y分量、U分量、V分量;

其中Y分量内存大小为:

Y分量buff_size = W * H ;

其中U分量内存大小为:

U分量buff_size = W/2 * H/2 ,即W * H /4 ;

其中V分量内存大小为:

V分量buff_size = W/2 * H/2 ,即W * H /4 ;

YV12图像大小 = Y分量大小 + U分量大小 +V分量大小

即:

YV12图像大小 =W * H *3/2

                                                     图-YV12(2)

NV12的理解

 NV12属于YUV420SP,即Y和UV分为两个Plane,但是UV为交错存储,而不是分为三个plane。对于NV12的图像上排列方式如图-NV12(1),首先是Y分量的排布,排布Y分量的宽为图像的宽(W),Y分量的高为图像的高(H);  其次是UV分量的交错排布。Y分量、UV分量依次排列。

Y0Y1Y2Y3Y4Y5Y6Y7
Y8Y9Y10Y11Y12Y13Y14Y15
Y16Y17Y18Y19Y20Y21Y22Y23
Y24Y25Y26Y27Y28Y29Y30Y31
U0V0U1V1U2V2U3V3
U4V4U5V5U6V6U7V7

                                                         图-NV12(1)

如 图-NV12(1)红色部分Y0、Y1、Y8、Y9共用U0和V0分量;依次类推,对应颜色的Y分量共用对应颜色的U和V分量。

NV12的内存排列,如图-NV12(2),依次是Y分量、U分量、V分量;

其中Y分量内存大小为:

Y分量buff_size = W * H ;

其中U分量内存大小为:

U分量buff_size = W/2 * H/2 ,即W * H /4 ;

其中V分量内存大小为:

V分量buff_size = W/2 * H/2 ,即W * H /4 ;

NV12图像大小 = Y分量大小 + U分量大小 +V分量大小

即:

YV12图像大小 =W * H *3/2

                                               图-NV12(2)

NV21的理解

 NV21属于YUV420SP,即Y和UV分为两个Plane,但是VU为交错存储,而不是分为三个plane。对于NV21的图像上排列方式如图-NV21(1),首先是Y分量的排布,排布Y分量的宽为图像的宽(W),Y分量的高为图像的高(H);  其次是VU分量的交错排布。Y分量、VU分量依次排列。

NV21与NV12 本质区别是V和U的先后区别。

Y0Y1Y2Y3Y4Y5Y6Y7
Y8Y9Y10Y11Y12Y13Y14Y15
Y16Y17Y18Y19Y20Y21Y22Y23
Y24Y25Y26Y27Y28Y29Y30Y31
V0U0V1U1V2U2V3U3
V4U4V5U5V6U6V7U7

                                                                        图-NV21(1)

如 图-NV21(1)红色部分Y0、Y1、Y8、Y9共用U0和V0分量;依次类推,对应颜色的Y分量共用对应颜色的U和V分量。

YV12的内存排列,如图-NV21(2),依次是Y分量、U分量、V分量;

其中Y分量内存大小为:

Y分量buff_size = W * H ;

其中U分量内存大小为:

U分量buff_size = W/2 * H/2 ,即W * H /4 ;

其中V分量内存大小为:

V分量buff_size = W/2 * H/2 ,即W * H /4 ;

NV21图像大小 = Y分量大小 + U分量大小 +V分量大小

即:

NV21​​​​​​​图像大小 =W * H *3/2

​​​​​​​

                                            图-NV21(2)

YV12​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​与I420颜色空间相互转换

由YV12和I420的内存排列可知,Y的排列方式是相同的,不同的是U和V的排列;YV12的排列依次是Y 、V 、U ;而I420的排列顺序依次是Y 、U 、V。由此可见只要改变U、V的排列顺序即可实现YV12与I420的相互转换。

转换代码

int YV12_2_I420(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_u = src + width * height;uint8_t* src_v = src + width * height * 5 / 4;uint8_t* dst_y = dst;uint8_t* dst_v = dst + width * height;uint8_t* dst_u = dst + width * height * 5 / 4;memcpy(dst_y, src_y, width * height);memcpy(dst_v, src_v, width * height / 4);memcpy(dst_u, src_u, width * height / 4);return 0;
}int I420_2_YV12(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_u = src + width* height;uint8_t* src_v = src + width * height*5/4;uint8_t* dst_y = dst;uint8_t* dst_v = dst + width * height;uint8_t* dst_u = dst + width * height * 5 / 4;memcpy(dst_y, src_y, width * height);memcpy(dst_v, src_v, width * height/4);memcpy(dst_u, src_u, width * height/4);return 0;
}

NV12与I420颜色空间相互转换

由NV12和I420的内存排列可知,Y的排列方式是相同的,不同的是U和V的排列;NV12的U、V是交错式排列排列顺序依次是Y、UV排列。而I420的U、V依次排序。由此可见只要改变U、V的排列顺序即可实现NV12与I420的相互转换。

转换代码

int I420_2_NV12(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_u = src + width * height;uint8_t* src_v = src + width * height * 5 / 4;uint8_t* dst_y = dst;uint8_t* dst_uv = dst + width * height;memcpy(dst_y, src_y, width * height);//UV交错排列for (int i = 0; i < width / 2 * height / 2; i++){dst_uv[2*i] = src_u[i];dst_uv[2 * i+1] = src_v[i];}return 0;
}int NV21_2_YV12(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_uv = src + width * height;uint8_t* dst_y = dst;uint8_t* dst_v = dst + width * height;uint8_t* dst_u = dst + width * height * 5 / 4;memcpy(dst_y, src_y, width * height);//UV交错排列for (int i = 0; i < width / 2 * height / 2; i++){dst_v[i] = src_uv[2 * i];dst_u[i] = src_uv[2 * i + 1];}return 0;
}

NV21与YV12颜色空间相互转换

由NV12和YV12的内存排列可知,Y的排列方式是相同的,不同的是U和V的排列;NV12的U、V是交错式排列排列顺序依次是Y、UV排列。而YV12的U、V依次排序。由此可见只要改变U、V的排列顺序即可实现NV12与I420的相互转换。基本与I420转换一样。

转换代码

int NV21_2_YV12(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_uv = src + width * height;uint8_t* dst_y = dst;uint8_t* dst_v = dst + width * height;uint8_t* dst_u = dst + width * height * 5 / 4;memcpy(dst_y, src_y, width * height);for (int i = 0; i < width / 2 * height / 2; i++){dst_v[i] = src_uv[2 * i];dst_u[i] = src_uv[2 * i + 1];}return 0;
}int YV12_2_NV21(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_v = src + width * height;uint8_t* src_u = src + width * height * 5 / 4;uint8_t* dst_y = dst;uint8_t* dst_uv = dst + width * height;memcpy(dst_y, src_y, width * height);for (int i = 0; i < width / 2 * height / 2; i++){dst_uv[2 * i] = src_v[i];dst_uv[2 * i + 1] = src_u[i];}return 0;
}

二、YUV转RGB

概述 

RGB32与RGB24整体排列方式是一致,RGB32比RGB24多了一个预留位。也称做A通道。

RGB32的理解

RGB32由图-RGB32(1)可以看出来,R、G、B、A组成一个像素点;同事一个像素点占4个字节;R、G、B、A是交错排列的。

R0G0B0A0R1G1B1A1R2G2B2A2R3G3B3A3R4G4B4A4R5G5B5A5R6G6B6A6R7G7B7A7
R8G8B8A8R9G9B9A9R10G10B10A10R11G11B11A11R12G12B12A12R13G13B13A13R14G14B14A14R15G15B15A15
R16G16B16A16R17G17B17A17R18G18B18A18R19G19B19A19R20G20B20A20R21G21B21A21R22G22B22A22R23G23B23A23
R24G24B24A24R25G25B25A25R26G26B26A26R27G27B27A27R28G28B28A28R29G29B29A29R30G30B30A30R31G31B31A31

                                                                                                                                                    图-RGB32(1)

RGB24的理解

RGB32由图-RGB24(1)可以看出来,R、G、B组成一个像素点;同事一个像素点占3个字节;R、G、B是交错排列的。

R0G0B0R1G1B1R2G2B2R3G3B3R4G4B4R5G5B5R6G6B6R7G7B7
R8G8B8R9G9B9R10G10B10R11G11B11R12G12B12R13G13B13R14G14B14R15G15B15
R16G16B16R17G17B17R18G18B18R19G19B19R20G20B20R21G21B21R22G22B22R23G23B23
R24G24B24R25G25B25R26G26B26R27G27B27R28G28B28R29G29B29R30G30B30R31G31B31

                                                                                                                                           图-RGB24(1)

I420与RGB32颜色空间相互转换

I420与RGB32相互转换不同于yuv的转换。I420 2行共用一个U分量和V分量。所以RGB转yuv的时候应该注意排列方式。

转换代码

typedef  struct  RGB32 {uint8_t     rgbBlue;       // 蓝色分量uint8_t     rgbGreen;      // 绿色分量uint8_t     rgbRed;        // 红色分量uint8_t     rgbReserved;   // 保留字节(用作Alpha通道或忽略)RGB32(){rgbBlue = 0;rgbGreen = 0;rgbRed = 0;rgbReserved = 0;}
} RGB32;int I420_2_rgb32(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_u = src + width * height;uint8_t* src_v = src + width * height * 5 / 4;RGB32* prgb = reinterpret_cast<RGB32*>(dst);int rgbindex = 0;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){RGB32* rgbNode = &prgb[rgbindex];//读取YUVuint8_t Y = src_y[y * width + x];uint8_t U = src_u[y / 2 * width / 2 + x / 2];uint8_t V = src_v[y / 2 * width / 2 + x / 2];//计算rgbint tmpr = Y + 1.402 * (V - 128);int tmpg = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128);int tmpb = Y + 1.772 * (U - 128);//越界保护rgbNode->rgbRed = tmpr > 255 ? 255 : (tmpr < 0 ? 0 : tmpr);rgbNode->rgbGreen =tmpg > 255 ? 255 : (tmpg < 0 ? 0 : tmpg);rgbNode->rgbBlue = tmpb > 255 ? 255 : (tmpb < 0 ? 0 : tmpb);rgbindex++;}}return 0;
}int rgb32_2_I420(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{RGB32* prgb = reinterpret_cast<RGB32*>(src);uint8_t* dst_y = dst;uint8_t* dst_u = dst + width * height;uint8_t* dst_v = dst + width * height * 5 / 4;//Y = 0.298R + 0.612G + 0.117B;//U = -0.168R - 0.330G + 0.498B + 128;//V = 0.449R - 0.435G - 0.083B + 128;int rgbindex = 0;int u_index = 0;int v_index = 0;int y_index = 0;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){rgbindex = y * width + x;RGB32* rgbNode = &prgb[rgbindex];//Y = 0.298R + 0.612G + 0.117B;int tmp_y = 0.298*rgbNode->rgbRed + 0.612 * rgbNode->rgbGreen + 0.117*rgbNode->rgbBlue;dst_y[y_index] = tmp_y > 255 ? 255 : (tmp_y < 0 ? 0 : tmp_y);y_index++;if (y%2 ==0 &&x%2 == 0){//U = -0.168R - 0.330G + 0.498B + 128;int tmp_u = -0.168 * rgbNode->rgbRed - 0.330 * rgbNode->rgbGreen + 0.498 * rgbNode->rgbBlue + 128;//V = 0.449R - 0.435G - 0.083B + 128;int tmp_v = 0.449 * rgbNode->rgbRed - 0.435 * rgbNode->rgbGreen + 0.083 * rgbNode->rgbBlue + 128;dst_u[u_index] = tmp_u > 255 ? 255 : (tmp_u < 0 ? 0 : tmp_u);dst_v[v_index] = tmp_v > 255 ? 255 : (tmp_v < 0 ? 0 : tmp_v);v_index++;u_index++;}}}return 0;
}

I420与RGB24颜色空间相互转换

rgb24与rgb32计算方式基本一致。却别在于rgb32每个像素点4字节;gb24每个像素点3字节。

转换代码

typedef  struct  RGB24 {uint8_t     rgbBlue;       // 蓝色分量uint8_t     rgbGreen;      // 绿色分量uint8_t     rgbRed;        // 红色分量RGB24(){rgbBlue = 0;rgbGreen = 0;rgbRed = 0;}
} RGB24;int I420_2_rgb24(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{uint8_t* src_y = src;uint8_t* src_u = src + width * height;uint8_t* src_v = src + width * height * 5 / 4;RGB24* prgb = reinterpret_cast<RGB24*>(dst);int rgbindex = 0;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){RGB24* rgbNode = &prgb[rgbindex];//读取YUVuint8_t Y = src_y[y * width + x];uint8_t U = src_u[y / 2 * width / 2 + x / 2];uint8_t V = src_v[y / 2 * width / 2 + x / 2];//计算rgb//R = Y + 1.4075(V - 128);//G = Y - 0.3455(U - 128) - 0.7169(V - 128);//B = Y + 1.779(U - 128);int tmpr = Y + 1.402 * (V - 128);int tmpg = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128);int tmpb = Y + 1.772 * (U - 128);//越界保护rgbNode->rgbRed = tmpr > 255 ? 255 : (tmpr < 0 ? 0 : tmpr);rgbNode->rgbGreen = tmpg > 255 ? 255 : (tmpg < 0 ? 0 : tmpg);rgbNode->rgbBlue = tmpb > 255 ? 255 : (tmpb < 0 ? 0 : tmpb);rgbindex++;}}return 0;
}int rgb24_2_I420(uint8_t* src, uint8_t* dst, uint32_t width, uint32_t height)
{RGB24* prgb = reinterpret_cast<RGB24*>(src);uint8_t* dst_y = dst;uint8_t* dst_u = dst + width * height;uint8_t* dst_v = dst + width * height * 5 / 4;//Y = 0.298R + 0.612G + 0.117B;//U = -0.168R - 0.330G + 0.498B + 128;//V = 0.449R - 0.435G - 0.083B + 128;int rgbindex = 0;int u_index = 0;int v_index = 0;int y_index = 0;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){rgbindex = y * width + x;RGB24* rgbNode = &prgb[rgbindex];//Y = 0.298R + 0.612G + 0.117B;int tmp_y = 0.298 * rgbNode->rgbRed + 0.612 * rgbNode->rgbGreen + 0.117 * rgbNode->rgbBlue;dst_y[y_index] = tmp_y > 255 ? 255 : (tmp_y < 0 ? 0 : tmp_y);y_index++;if (y % 2 == 0 &&x % 2 == 0){//U = -0.168R - 0.330G + 0.498B + 128;int tmp_u = -0.168 * rgbNode->rgbRed - 0.330 * rgbNode->rgbGreen + 0.498 * rgbNode->rgbBlue + 128;//V = 0.449R - 0.435G - 0.083B + 128;int tmp_v = 0.449 * rgbNode->rgbRed - 0.435 * rgbNode->rgbGreen + 0.083 * rgbNode->rgbBlue + 128;dst_u[u_index] = tmp_u > 255 ? 255 : (tmp_u < 0 ? 0 : tmp_u);dst_v[v_index] = tmp_v > 255 ? 255 : (tmp_v < 0 ? 0 : tmp_v);v_index++;u_index++;}}}return 0;
}

 三、代码路径

csdn:https://download.csdn.net/download/u011645307/21113273

github:https://github.com/liangqidong/ColorConversion.git

这篇关于视音频数据处理入门:颜色空间(一)---转换理解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/295220

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

MySQL之InnoDB存储页的独立表空间解读

《MySQL之InnoDB存储页的独立表空间解读》:本文主要介绍MySQL之InnoDB存储页的独立表空间,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、独立表空间【1】表空间大小【2】区【3】组【4】段【5】区的类型【6】XDES Entry区结构【

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

利用Python脚本实现批量将图片转换为WebP格式

《利用Python脚本实现批量将图片转换为WebP格式》Python语言的简洁语法和库支持使其成为图像处理的理想选择,本文将介绍如何利用Python实现批量将图片转换为WebP格式的脚本,WebP作为... 目录简介1. python在图像处理中的应用2. WebP格式的原理和优势2.1 WebP格式与传统

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE