原文链接:1.https://www.cnblogs.com/hoodlum1980/archive/2010/10/27/1862955.html

2.https://www.0xaa55.com/thread-293-1-1.html

先声明下,我只是简单复制合并了上面两个链接的内容,自己没动手试过。只是最近看到了调色盘的东西,对调色盘的概念和算法不太了解,这里只是简单记录下。

链接2的正文:(调色盘的概念和八叉树算法的原理)

在一些特殊情况,我们需要将位图从24位真彩色压缩成256色。调色板的选取就变得很重要了,因为调色板决定了这256个颜色是什么样的颜色。
如果一个以红色为主的位图用了蓝色较多的调色板,那么它的显示效果就会变得很差。因此,我们需要用一个比较好的算法来取得合适的调色板。这就是八叉树算法。
八叉树算法的原理是通过建立一个“八叉树”,将图像中的颜色添加进八叉树,当颜色数量超过256色的时候合并八叉树的树叶,从而减少颜色。最终产生的256个颜色将是最适合这个图片的颜色。

实现原理:

八叉树算法要建立一个八叉树,每个节点有8个子节点,共8级,一级一级的延伸下去,最后一级是“树叶”。

当你得到一张图片的时候,你需要把图片的每一个颜色添加进八叉树。怎么添加呢?首先你需要取得颜色的RGB值。
假定图片是24位真彩色,红绿蓝各占8位,也就是一个字节一个颜色值。这里举个例子,假设颜色是淡蓝色(红:240,绿:250,蓝:255),右边括号里的字就是这种颜色(你居然看到了!)
然后,你把红绿蓝的字节按照如下图的方式看:

颜色值的二进制位数 第7位 第6位 第5位 第4位 第3位 第2位 第1位 第0位
红色字节 1 1 1 1 0 0 0 0
绿色字节 1 1 1 1 1 0 1 0
蓝色字节 1 1 1 1 1 1 1 1

现在我们要做的就是把这张表中的数字竖着看,从各个位中间取出3个二进制位,组成一个0到7之间整数,然后这个整数就是这个颜色在八叉树中对应级的位置。看看上面的表,按照这样说的,第7位的三个二进制位组成数字111(十进制的7),那么我们就在八叉树的第0级第7个子节点处添加一个节点,然后第6位的三个二进制位组成数字111(十进制的7),那么我们就在八叉树的第1级第7个子节点处添加一个节点,以此类推。这样八叉树的树叶就在不断增多。当八叉树的树叶数量到达256的时候,我们就需要把一些叶子合并。通常就合并最后添加的颜色所在树枝的树叶。先合并树叶,合并完了再网上合并树枝。
最后,所有颜色采集完了以后,就遍历整个八叉树,取出所有树叶的颜色,这样就得到了调色板。

链接1的正文:(主要是八叉树算法的实现和结果)

本文介绍的内容,是用八叉树法降级一个真彩色图像(BPP=16以上)。这也是某公司在今年校园招聘中的笔试中的最后一道题目。我参考了 Jeff Prosise 所写的这篇文章(见参考资料),然后修改了他提供的范例的源码,使能够更好的演示该算法,同时我也添加了绘制八叉树的代码,可以直观的看到八叉树的形态。

    索引图像的尺寸比真彩色图像可以大幅降低,保存为256色索引图像大约只有真彩色图像的1/3 (bpp = 24) 或 1/4 (bpp = 32),因为表示每个像素的数据从3或4个字节减少到1个字节。如果保存为16色索引图像则还能减小一半尺寸,不过16色图像的质量相比真彩图像实在过低,一般除非硬件限制(比如TC那样的图形模式下),在现在的条件下是很少再会用到的。它可以用在需要降级图像质量的场合,例如,如果我们生成一个图标,根据提供真彩色图像,然后根据此图像创建出的其他质量等级的图标图像。

             【原创性声明】

    本文提到的算法和原始范例的源码来自参考文献。以下部分属于我增加的代码:

    (a)对八叉树的绘制以及生成动画;

    (b)在不需要修改显示器模式的条件下展示八叉树算法生成的索引图像(原范例需要先把显示器调整为256色模式才能看到效果);

    (c)把真彩色位图通过八叉树算法保存为 BMP 索引位图文件。

    对该算法的介绍请参考 Jeff Prosise 的文档,是英文的,那篇文章中讲解了该算法的核心思想,我在这里不做重复介绍。根据文档的内容,八叉树算法最早是在1988, M. Gervautz 和 W. Purgathofer 发表的论文《A Simple Method for Color Quantization: Octree Quantization.》中首次介绍的。这个算法非常简洁优美,其优美之处在于从一副具有很多色彩的图像中,提取出最能完美表达该图像颜色的调色板的过程。这个过程就是一个八叉树的生长和节点合并的过程。该算法的最大优点是效率高,占用内存少(仅需要不超过 颜色数量+1 个节点,加上一些中间节点所占用的内存),选出的调色板最合理,显示效果最好。比流行方法(扫描图像然后取最多像素数量的颜色组成调色板)好很多。下图就是从我修改后的范例的展示出来的结果而来,我重新排列了一下图像:

    

    为了我想要的展示,我调整了原来范例的代码,提供了一个根据真彩色位图,创建出八叉树的代码,该代码主要来源于原来的范例,该算法的核心是用RGB通道的相应的位组成子结点的索引(从高位开始提取RGB分量中的位),来让树生长。遍历图像的像素,根据当前像素的RGB分量导航到一个叶子节点(如果不存在则创建它),然后把当前像素的RGB分量累加到该节点的相应Sum值,并使节点代表的像素数量递增。每当叶子节点数量(代表一种颜色)超出最大颜色数量时,就选出一个最深的非叶子节点,将其收缩为叶子节点,最终的颜色值是用RGB分量的总和除以该节点代表的像素数量来得到的。可见,在多个相近的不同颜色降级成用同一个调色板颜色来表示时,调色板颜色是在它们之间取了一个加权平均(这种加权平均使原图中的一些“平滑渐变”变成了色带,例如上图中女模特面部的“等高线”效果),以达到表达图像本质的最佳效果。该算法中不需要统计整个图像的直方图也不需要排序,所以不会产生较大的内存需求。尽管真彩色图像可能具有大量的像素,大量的颜色数量,但它的颜色信息被集中统计在一颗较小的树的叶子节点上,该树的动态调整策略使得它总是反应着当前时刻的最佳选择,遍历像素时,结果以非常完美的方式进行“积累”(你不必担心统计结果被覆盖而不得不申请更多独立空间),这正是算法的优美之处。(代码中引用到的某些辅助方法在此省略):

//根据一个图像,创建一个八叉树,hoodlum1980 add;
NODE* BuildOctree(HANDLE hImage, UINT nMaxColors, UINT nColorBits)
{DIBSECTION ds;int i, j, nPad;BYTE* pbBits;WORD* pwBits;DWORD* pdwBits;DWORD rmask, gmask, bmask;int rright, gright, bright;int rleft, gleft, bleft;BYTE r, g, b;WORD wColor;DWORD dwColor;NODE* pTree;UINT nLeafCount, nIndex;NODE* pReducibleNodes[9];// Initialize octree variablesg_nMaxPixelCount = 0;pTree = NULL;nLeafCount = 0;if (nColorBits > 8) // Just in casereturn NULL;for (i=0; i<=(int) nColorBits; i++)pReducibleNodes[i] = NULL;// Scan the DIB and build the octreeGetObject (hImage, sizeof (ds), &ds);nPad = ds.dsBm.bmWidthBytes - (((ds.dsBmih.biWidth *ds.dsBmih.biBitCount) + 7) / 8);switch (ds.dsBmih.biBitCount) {case 16: // One case for 16-bit DIBsif (ds.dsBmih.biCompression == BI_BITFIELDS) {rmask = ds.dsBitfields[0];gmask = ds.dsBitfields[1];bmask = ds.dsBitfields[2];}else {rmask = 0x7C00;gmask = 0x03E0;bmask = 0x001F;}rright = GetRightShiftCount (rmask);gright = GetRightShiftCount (gmask);bright = GetRightShiftCount (bmask);rleft = GetLeftShiftCount (rmask);gleft = GetLeftShiftCount (gmask);bleft = GetLeftShiftCount (bmask);pwBits = (WORD*) ds.dsBm.bmBits;for (i=0; i<ds.dsBmih.biHeight; i++) {for (j=0; j<ds.dsBmih.biWidth; j++) {wColor = *pwBits++;b = (BYTE) (((wColor & (WORD) bmask) >> bright) << bleft);g = (BYTE) (((wColor & (WORD) gmask) >> gright) << gleft);r = (BYTE) (((wColor & (WORD) rmask) >> rright) << rleft);AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,pReducibleNodes);while (nLeafCount > nMaxColors)ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);}pwBits = (WORD*) (((BYTE*) pwBits) + nPad);}break;case 24: // Another for 24-bit DIBspbBits = (BYTE*) ds.dsBm.bmBits;for (i=0; i<ds.dsBmih.biHeight; i++) {for (j=0; j<ds.dsBmih.biWidth; j++) {//*pbBits = 0xff;b = *pbBits++;g = *pbBits++;r = *pbBits++;AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,pReducibleNodes);while (nLeafCount > nMaxColors)ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);}pbBits += nPad;}break;case 32: // And another for 32-bit DIBsif (ds.dsBmih.biCompression == BI_BITFIELDS) {rmask = ds.dsBitfields[0];gmask = ds.dsBitfields[1];bmask = ds.dsBitfields[2];}else {rmask = 0x00FF0000;gmask = 0x0000FF00;bmask = 0x000000FF;}rright = GetRightShiftCount (rmask);gright = GetRightShiftCount (gmask);bright = GetRightShiftCount (bmask);pdwBits = (DWORD*) ds.dsBm.bmBits;for (i=0; i<ds.dsBmih.biHeight; i++) {for (j=0; j<ds.dsBmih.biWidth; j++) {dwColor = *pdwBits++;b = (BYTE) ((dwColor & bmask) >> bright);g = (BYTE) ((dwColor & gmask) >> gright);r = (BYTE) ((dwColor & rmask) >> rright);AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,pReducibleNodes);while (nLeafCount > nMaxColors)ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);}pdwBits = (DWORD*) (((BYTE*) pdwBits) + nPad);}break;default: // DIB must be 16, 24, or 32-bit!return NULL;}// 现在第二次遍历像素,把它复成调色板的值~//得到调色板nIndex = 0;GetRGBQUADs (pTree, g_pColors, &nIndex);g_nColorCount_Real = nIndex; //实际调色板数量(小于等于最大颜色数量)return pTree;
}void AddColor (NODE** ppNode, BYTE r, BYTE g, BYTE b, UINT nColorBits,UINT nLevel, UINT* pLeafCount, NODE** pReducibleNodes)
{int nIndex, shift;static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };// If the node doesn't exist, create itif (*ppNode == NULL)*ppNode = CreateNode (nLevel, nColorBits, pLeafCount,pReducibleNodes);// Update color information if it's a leaf nodeif ((*ppNode)->bIsLeaf) {(*ppNode)->nPixelCount++;(*ppNode)->nRedSum += r;(*ppNode)->nGreenSum += g;(*ppNode)->nBlueSum += b;if((*ppNode)->nPixelCount > g_nMaxPixelCount)g_nMaxPixelCount = (*ppNode)->nPixelCount;}// Recurse a level deeper if the node is not a leafelse {shift = 7 - nLevel;nIndex = (((r & mask[nLevel]) >> shift) << 2) |(((g & mask[nLevel]) >> shift) << 1) |((b & mask[nLevel]) >> shift);AddColor (&((*ppNode)->pChild[nIndex]), r, g, b, nColorBits,nLevel + 1, pLeafCount, pReducibleNodes);}
}NODE* CreateNode (UINT nLevel, UINT nColorBits, UINT* pLeafCount,NODE** pReducibleNodes)
{NODE* pNode;if ((pNode = (NODE*) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,sizeof (NODE))) == NULL)return NULL;pNode->bIsLeaf = (nLevel == nColorBits) ? TRUE : FALSE;if (pNode->bIsLeaf)(*pLeafCount)++;else { // Add the node to the reducible list for this levelpNode->pNext = pReducibleNodes[nLevel];pReducibleNodes[nLevel] = pNode;}return pNode;
}void ReduceTree (UINT nColorBits, UINT* pLeafCount, NODE** pReducibleNodes)
{int i;NODE* pNode;UINT nRedSum, nGreenSum, nBlueSum, nChildren;// Find the deepest level containing at least one reducible nodefor (i=nColorBits - 1; (i>0) && (pReducibleNodes[i] == NULL); i--);// Reduce the node most recently added to the list at level ipNode = pReducibleNodes[i];pReducibleNodes[i] = pNode->pNext;nRedSum = nGreenSum = nBlueSum = nChildren = 0;for (i=0; i<8; i++) {if (pNode->pChild[i] != NULL) {nRedSum += pNode->pChild[i]->nRedSum;nGreenSum += pNode->pChild[i]->nGreenSum;nBlueSum += pNode->pChild[i]->nBlueSum;pNode->nPixelCount += pNode->pChild[i]->nPixelCount;HeapFree (GetProcessHeap (), 0, pNode->pChild[i]);pNode->pChild[i] = NULL;nChildren++;}}pNode->bIsLeaf = TRUE;pNode->nRedSum = nRedSum;pNode->nGreenSum = nGreenSum;pNode->nBlueSum = nBlueSum;//更新节点的最大像素数量。if(pNode->nPixelCount > g_nMaxPixelCount)g_nMaxPixelCount = pNode->nPixelCount;*pLeafCount -= (nChildren - 1);
}

备注:上面代码中,树节点的定义如下:

    typedef struct _NODE {BOOL bIsLeaf;               // TRUE if node has no children (是否是叶子节点)UINT nPixelCount;           // Number of pixels represented by this leaf (代表的像素数量)UINT nRedSum;               // Sum of red componentsUINT nGreenSum;             // Sum of green componentsUINT nBlueSum;              // Sum of blue components (B通道分量总和)struct _NODE* pChild[8];    // Pointers to child nodes  (子结点)struct _NODE* pNext;        // Pointer to next reducible nodeBYTE nColorIndex;             // 仅对叶子节点有效,表示此节点代表的颜色在调色板中的索引!存储到BMP文件时有用。} NODE;

上面的方法返回一个八叉树的根节点指针,然后我们就可以根据这棵树,生成索引图像和调色板,方法是重新遍历图像,根据RGB的值,在树之间向更深的方向导航,直到遇到叶子节点,那么叶子节点上可以计算出该像素在索引图像的中的RGB值。在另存为 BMP 时,这个RGB值被放到索引图像的调色板中。下面的方法,我用一个24BPP的像素数据去模拟出索引图像的显示效果,因此 g_lpBits 是一块24bpp的图像处理,但是我将它设置成降级后的颜色,并在窗口中展示出来:

//生成八叉树降级后的位图
void CreateOctreeBitmap (NODE* pTree, UINT nMaxColors, UINT nColorBits)
{int bpp = g_BmInfo.bmiHeader.biBitCount;static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };// 现在第二次遍历像素,把它复成调色板的值~int i, j;UINT nIndex, nLevel, shift;NODE* pNode = NULL;BYTE *pbBits, r, g, b;int stride = (g_BmInfo.bmiHeader.biWidth * bpp + 31)/32 *4;int nPad = stride - (g_BmInfo.bmiHeader.biWidth *bpp + 7) / 8;if(bpp == 24 || bpp == 32){pbBits = (BYTE*) g_lpBits;for (i=0; i<g_BmInfo.bmiHeader.biHeight; i++) {for (j=0; j<g_BmInfo.bmiHeader.biWidth; j++) {//*pbBits = 0xff;b = *pbBits;g = *(pbBits+1);r = *(pbBits+2);pNode = pTree;nLevel = 0;while(!pNode->bIsLeaf){shift = 7 - nLevel;nIndex = (((r & mask[nLevel]) >> shift) << 2) |(((g & mask[nLevel]) >> shift) << 1) |((b & mask[nLevel]) >> shift);pNode = pNode->pChild[nIndex];nLevel++;}//取颜色*pbBits = (BYTE)(pNode->nBlueSum/pNode->nPixelCount);*(pbBits+1)= (BYTE)(pNode->nGreenSum/pNode->nPixelCount);*(pbBits+2)= (BYTE)(pNode->nRedSum/pNode->nPixelCount);pbBits += (bpp/8);}pbBits += nPad;}}return;
}

    该算法如果选择的颜色数量太低(比如低于4),则很可能最终整个图像只有一种颜色,这是因为算法为了满足不超过颜色数量的要求,在收缩子结点时,使一次收缩多个子结点的(最多可以从 8 个叶子结点收缩成1个叶子节点,即 8 个调色板颜色降低为 1 个),可见这种节点收缩使得调色板颜色数量的变化是“跳跃性”的,因此实际调色板的颜色数量不一定总是等于设置的最大颜色数量,有时实际颜色数量会比设定的最大颜色数量小。所以通常也不能期待八叉树法能生成只有两种颜色数量的二元位图(从某个最低颜色数量开始可能会“突变”到全图都被一种颜色填充)。二元位图通常是通过选定一个阈值去重设像素得到的。

    最后是用我的代码绘制出的八叉树效果,绘制是通过递归函数来完成的,这个代码并不复杂,这里我就不贴了。在这里假设每个节点具有一个面向的方向,例如根节点是面向下方生长,其角度就是PI/2。然后向八个角度方向生长出子结点,通过递归调用绘制出整个树,中间节点是空白的圆形,叶子节点代表调色板中的一个颜色,并且用该调色板颜色填充。

    通过调整参数(树枝长短,节点占据的角度等)可以绘制出各种形态的八叉树,在源码中我把代表像素数量较多的节点绘制的更大一些,代表像素数量少的绘制小一些。下面是一些早期绘制出来的八叉树,中间的一副因为设置的子结点角度关系,不能看出根节点在何处。右边的一幅图,因为子结点伸展角度小且树枝较长,所以能很清晰的看出节点在树中的深度。下图中我根据我自己的第一印象分别取了名字,现在再看,左边和右边的也好像鸡冠花,菜花,扇子,中间的好像城市地铁交通图,右侧的叫做裙子是因为感觉好像女生跳舞用的舞裙。我还制作出八叉树的生成和合并过程的动画(有这个想法是因为我曾经看到别人写的八皇后算法的树生成动画),使用菜单View中的查看动画,即可看到八叉树算法过程中树的动态变化过程(为了加快动画过程,这部分功能可能并没有完整遍历图像,因此动画中产生的树可能和查看八叉树的树有所不同)。

    源码下载:    

    最后是我修改后的范例的源码下载连接:(该范例可以把降级后的结果保存为BMP格式的索引图像)

    http://files.cnblogs.com/hoodlum1980/Colors_src.rar

    这里简单介绍该范例的使用方法,用菜单打开,打开一个真彩色的BMP位图,然后点击Optimized Palette 菜单可以弹出一个对话框,在该对话框中,设置的第一项 SignicantColorBits 表示八叉树的深度可以最大达到多大(1~8,默认值为6),在颜色被降级以后,由于树的深度会减小,所以该值设置的太大的话也没有什么意义。MaxColorCount 表示索引图像最多的颜色数量(1~256)。其他两个为显示值,一个是实际调色板数量,在保存为BMP索引图像时,我将使用八叉树代表的实际的调色板数量(而不是固定为16或者256)。另一个是表示八叉树中的所有叶子节点中,每个叶子节点都有一个属性:所代表的像素数量,g_nMaxPixelCount 表示的它们中的最大值。在生成索引图像以后,即可看到下方显示出索引图像的视觉效果,右侧是其调色板。在View菜单中点击“重新绘制八叉树图”,即可看到我绘制的八叉树的图像。通过View下面的其他两个菜单切换显示位图或者八叉树图。

    这里是原始范例的代码:

    http://www.microsoft.com/msj/archive/s3f1a.htm

    注意,如果要使用这个程序之前,必须先把显示器调整到256色模式(XP中隐藏了低级别模式,需要点击监视器的高级按钮),然后点击Option下面的菜单可以看到不同调色板对应的索引图像效果。另外,这个网址仅仅提供的是源码,需要自己创建 Windows 应用程序工程。

    参考资料:

    (1)http://www.microsoft.com/msj/archive/S3F1.aspx;

      <<wicked code>> -- Jeff Prosise

    维护记录:

    (1)增加八叉树动画演示效果。2010-10-29。

    BYTHEWAY:再添加动画功能时,我无意中犯了一个“GDI 对象泄露”的BUG,由于创建的 HBRUSH 没有全部被 Delete,导致输出的帧数达到 140 以上时,窗口开始显示异常。我画了很大精力才定位到这个 BUG 并将其修复。。。

调色盘——将真彩色图像降级为低分辨率图像的八叉树算法相关推荐

  1. MATLAB(完备)之图像.tif到真彩色图像、索引色图像、灰度图像、 真彩色图像RGB、YIQ图像、HSV图像、YCbCr图像转换代码

    I=imread('flower.tif');%读入图片 whos I imfinfo('flower.tif') imshow(I);title('原始tif图像') %%真彩图像.转索图像.灰度图 ...

  2. 真彩色图像,索引色图像,灰度图像, 二值图像之间的相互变换(Matlab实现)

    根据图像数据矩阵解释方法的不同,MATLAB 把其处理为 4 类: RGB 图像(Binary images): 一幅 RGB 图像就是彩色像素的一个 M×N×3 数组,其中每一个彩色相似点都是在特定 ...

  3. RGB 真彩色图像,CMYK 出版图像,YCbCr,L灰度图像

    RGB RGB色彩模式是工业界的一种颜色标准,是通过对红(R).绿(G).蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红.绿.蓝三个通道的颜色,这个标准几乎包 ...

  4. 第16章 调色盘管理器

    如果硬件允许,本章就没有存在的必要.尽管许多现代的显示卡提供24位颜色(也称「true color」或「数百万色」)或16位颜色(「增强色」或「数万种颜色」),一些显示卡-尤其是在便携式计算机上或高分 ...

  5. 原生JS搭配canvas模式开发的调色盘

    之前做了一版纯div版的,有同学反应加载速度太慢.无可否认,1W多个div能不慢么.做那个版本的用意在于...好玩, 好了,同样废话不多说,这次先上图吧! 风格是学习的谷歌的,一眼就看得出来,由于IE ...

  6. 009_调色盘和高亮样式

    1. color调色盘 1.1. 调色盘, 可以在option中设置.它给定了一组颜色, 图例.系列会自动从其中选择颜色.可以设置全局的调色盘, 也可以设置系列自己专属的调色盘. option = { ...

  7. echarts(一)下载引入,调色盘,[标题、图例组件、坐标轴]

    一个简单的例子 1. 下载并引入 (1)npm install echarts --save (2)import echarts from 'echarts' //main.js引入echarts 或 ...

  8. 图表可视化seaborn风格和调色盘

    seaborn是基于matplotlib的python数据可视化库,提供更高层次的API封装,包括一些高级图表可视化等工具. 使用seaborn需要先安装改模块pip3 install seaborn ...

  9. 真彩色图像数据量 计算_军职在线大学计算机基础(自主模式)

    第一章 单选题 电子计算机的发展已经经过了4代,4代计算机的主要元器件分别是(b) a.电子管,晶体管,中小规模集成电路,激光器件 b.电子管,晶体管,中小规模集成电路,大规模或超大规模集成电路 c. ...

  10. python plot map_python的colormap总结(matplotlib+ncl+气象家园调色盘)

    colormap又叫colorbar是一个包含三列矩阵的色彩映射表,简单来说就是一个shape为(N,3)的矩阵. 矩阵中的值的值取值范围为[0,1] 每一行代表一个颜色,即RGB值 1.matplo ...

最新文章

  1. mysql localhost无法登陆_MySQL 'root'@'localhost'无法登录
  2. 水果电商小程序云开发,从零到上线投入使用
  3. Python学习心得第一周-03练习1
  4. 在SQL2008中清除日志
  5. 高度平衡二叉树的构建_平衡二叉树建立及其增删改查(JAVA)
  6. mac设置截图和录屏的快捷键
  7. postgresql数据库用户名密码验证失败
  8. 花三千块钱求推荐一个靠谱的C++工程师
  9. vue 文件转换二进制_Vue利用Blob下载原生二进制数组文件
  10. JAVA运行时异常及常见的5中RuntimeExecption
  11. 多闪实名举报河南法院;ofo 内部发反腐文件;库克访华点赞故宫 App | 极客头条...
  12. oracle报错对象不存在
  13. DMA内存申请--dma_alloc_coherent 及 寄存器与内存【转】
  14. 屋面光伏荷载计算机构,光伏系统屋顶荷载计算
  15. oracle插入获取当前时间,Oracle中如何获取系统当前时间
  16. L2十档行情逐笔成交数据实战技巧
  17. python彩虹图_python绘制彩虹图教程
  18. 教你刷各大android手机应用市场下载排名
  19. matplotlib图例中文乱码? 标题部分可以通过设置字体属性解决,但是图例不支持设置字体,该如何解决
  20. 安全帽识别系统的应用

热门文章

  1. 如何为您的ADC选择最合适的基准电压源和放大器
  2. 安卓平板usb变显示器_三星DeX—安卓生产力之巅
  3. (译)Xposed Helpers
  4. 浅析DNS劫持和HTTP劫持
  5. 如何检测ajax完成且是成功的,检测ajax调用是否成功
  6. jetlinks之Thing(六)
  7. VMware vRealize Suite 8.8.0
  8. IOS端APP测试日志查看方法
  9. 应届生如何准备校招【研发岗】
  10. 【IoT】产品设计:用实际案例,手把手教你写MRD(市场需求文档)