本文作者:小嗷

微信公众号:aoxiaoji

关键词:颜色空间缩减和计时函数【两个简便的计时函数—getTickCount()和getTickFrequency()】


  1. 计时函数用途:计算耗时工作

  2. 颜色空间缩减用途:颜色空间缩减。(公式如下)

  1. 如何遍历图像中的每一个像素点? 请看第8篇代码【更正曝光不足的图像(图像的对比度和亮度及轨迹条)】
  2. OpenCv的矩阵值是如何存储的? 请看第9篇恶心的内容【基本的图像容器(Mat详解)】
  3. 如何测试我们所实现算法的性能?通过算法耗时和效果的对比【计时函数】
  4. 查找表是什么?为什么要用它?等一下,会说到。

图像矩阵的大小取决于我们使用的颜色模型,确切的说,取决于所用通道数。如果是灰度图像,矩阵就会像这样:

而对于多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相等,例如,RGB颜色模型的矩阵:

在这里,我们需要注意的是:子列的通道顺序是反过来的,是BGR,而不是我们数字图像书中常说的RGB.很多情况下,因为内存够大,可以实现连续存储。连续存储可以提高图像的扫描速度。我们可以使用isContinuous来判断矩阵是否连续矩阵。

3.1 颜色空间的缩减

如果矩阵元素存储的是单通道像素,使用C或C++的无符号字符类型,那么像素可能有256个不同的值.但若是三通道图像,这种存储格式的颜色数就太多了(确切的说,有一千六百多万种).用如此之多的颜色 可能会对我们算法的性能造成严重的影响。其实,有时候,我们仅适用这些颜色的一小部分,就足以达到同样的效果。

这种情况下,常用的一种方法就是【颜色空间缩减】.其做法是:将现有颜色值除以某个输入值,以获得较少的颜色数。例如:0到9可取新值0;10到19取值1,以此类推。

uchar(无符号字符,即0到255之间取值的数)类型除以int值,结果仍为char。因为结果是char类型的, 所以,求出来小数也要向下取整。利用这一点,刚才提到在uchar定义域中进行颜色缩减运算就可以表达为下列形式:

Inew=Iold/10*10;

这样的话,简单的颜色缩减算法就可以由以下两步组成:

1–遍历图像矩阵中的每一个像素 (第8篇用过)

2–对像素应用上述公式

值得注意的是,我们这里用到了除法和乘法运算,而这种运算又特别费时,所以,我们应尽可能用代价较低的加减,赋值等运算替换他们。

3.2 计时函数

  1. OpenCv为我们提供了两个简单的计时函数—getTickCount()和getTickFrequency()
  2. getTickCount()函数—返回CPU自某个事件以来走过的—-时钟周期数
  3. getTickFrequency()函数返回CUP一秒钟所走的时钟周期数。这样,我们就可以轻松的以秒为单位对某运算计时

这两个函数组合起来的使用如下所示:

//【5】记录其实时间
double timeStartPtr=static_cast<double>(getTickCount());
//【6】调用颜色空间缩减函数
colorReducePtr(srcImg,dstImgPtr,32);
//【7】计算运行时间,并输出
double timeExpensePtr=((double)getTickCount()-timeStartPtr)/getTickFrequency();
cout<<"【1】ptr指针操作像素,此方法运行时间为---------->"<<timeExpensePtr<<endl;

我一般都是复制粘贴计时函数,哈哈哈

3.3 访问图像中像素的三类方法

任何图像处理算法。都是从操作每个像素开始的。即使我们不会使用OpenCv提供的各种图像处理函数,只要我们了解图像处理算法的基本原理,也可以写出具有相同功能的程序.在OpenCv中,提供了三种访问每个像素的方法:

1--指针访问----------ptr<>()函数
2--动态地址计算------at<>()函数
3--迭代器iterator
这三种方法,在访问速度上略有差异,指针比较快。

//      程序描述:来自一本国外OpenCV2书籍的示例-遍历图像像素的14种方法
//------------------------------------------------------------------------------------------------/*------------------------------------------------------------------------------------------*\
This file contains material supporting chapter 2 of the cookbook:
Computer Vision Programming using the OpenCV Library.
by Robert Laganiere, Packt Publishing, 2011.This program is free software; permission is hereby granted to use, copy, modify,
and distribute this source code, or portions thereof, for any purpose, without fee,
subject to the restriction that the copyright notice may not be removed
or altered from any source or altered source distribution.
The software is released on an as-is basis and without any warranties of any kind.
In particular, the software is not guaranteed to be fault-tolerant or free from failure.
The author disclaims all warranties with regard to this software, any use,
and any consequent failure, is purely the responsibility of the user.Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*///---------------------------------【头文件、命名空间包含部分】-----------------------------
//      描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;//---------------------------------【宏定义部分】---------------------------------------------
//      描述:包含程序所使用宏定义
//-------------------------------------------------------------------------------------------------
#define NTESTS 14
#define NITERATIONS 20//----------------------------------------- 【方法一】-------------------------------------------
//      说明:利用.ptr 和 []
//-------------------------------------------------------------------------------------------------
void colorReduce0(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j<nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++){//-------------开始处理每个像素-------------------data[i] = data[i] / div*div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                  }
}//-----------------------------------【方法二】-------------------------------------------------
//      说明:利用 .ptr 和 * ++
//-------------------------------------------------------------------------------------------------
void colorReduce1(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j<nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++){//-------------开始处理每个像素-------------------*data++ = *data / div*div + div / 2;//-------------结束像素处理------------------------} //单行处理结束              }
}//-----------------------------------------【方法三】-------------------------------------------
//      说明:利用.ptr 和 * ++ 以及模操作
//-------------------------------------------------------------------------------------------------
void colorReduce2(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j<nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++){//-------------开始处理每个像素-------------------int v = *data;*data++ = v - v%div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//----------------------------------------【方法四】---------------------------------------------
//      说明:利用.ptr 和 * ++ 以及位操作
//----------------------------------------------------------------------------------------------------
void colorReduce3(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 对于 div=16, mask= 0xF0for (int j = 0; j<nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++) {//------------开始处理每个像素-------------------*data++ = *data&mask + div / 2;//-------------结束像素处理------------------------}  //单行处理结束            }
}//----------------------------------------【方法五】----------------------------------------------
//      说明:利用指针算术运算
//---------------------------------------------------------------------------------------------------
void colorReduce4(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));int step = image.step; //有效宽度//掩码值uchar mask = 0xFF << n; // e.g. 对于 div=16, mask= 0xF0//获取指向图像缓冲区的指针uchar *data = image.data;for (int j = 0; j<nl; j++){for (int i = 0; i<nc; i++){//-------------开始处理每个像素-------------------*(data + i) = *data&mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束              data += step;  // next line}
}//---------------------------------------【方法六】----------------------------------------------
//      说明:利用 .ptr 和 * ++以及位运算、image.cols * image.channels()
//-------------------------------------------------------------------------------------------------
void colorReduce5(Mat &image, int div = 64) {int nl = image.rows; //行数int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 例如div=16, mask= 0xF0for (int j = 0; j<nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i<image.cols * image.channels(); i++){//-------------开始处理每个像素-------------------*data++ = *data&mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束            }
}// -------------------------------------【方法七】----------------------------------------------
//      说明:利用.ptr 和 * ++ 以及位运算(continuous)
//-------------------------------------------------------------------------------------------------
void colorReduce6(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量if (image.isContinuous()){//无填充像素nc = nc*nl;nl = 1;  // 为一维数列}int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0for (int j = 0; j<nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++) {//-------------开始处理每个像素-------------------*data++ = *data&mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//------------------------------------【方法八】------------------------------------------------
//      说明:利用 .ptr 和 * ++ 以及位运算 (continuous+channels)
//-------------------------------------------------------------------------------------------------
void colorReduce7(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数if (image.isContinuous()){//无填充像素nc = nc*nl;nl = 1;  // 为一维数组}int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0for (int j = 0; j<nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i<nc; i++) {//-------------开始处理每个像素-------------------*data++ = *data&mask + div / 2;*data++ = *data&mask + div / 2;*data++ = *data&mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                    }
}// -----------------------------------【方法九】 ------------------------------------------------
//      说明:利用Mat_ iterator
//-------------------------------------------------------------------------------------------------
void colorReduce8(Mat &image, int div = 64) {//获取迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();Mat_<Vec3b>::iterator itend = image.end<Vec3b>();for (; it != itend; ++it) {//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] / div*div + div / 2;(*it)[1] = (*it)[1] / div*div + div / 2;(*it)[2] = (*it)[2] / div*div + div / 2;//-------------结束像素处理------------------------}//单行处理结束
}//-------------------------------------【方法十】-----------------------------------------------
//      说明:利用Mat_ iterator以及位运算
//-------------------------------------------------------------------------------------------------
void colorReduce9(Mat &image, int div = 64) {// div必须是2的幂int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如 div=16, mask= 0xF0// 获取迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//扫描所有元素for (; it != itend; ++it){//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] & mask + div / 2;(*it)[1] = (*it)[1] & mask + div / 2;(*it)[2] = (*it)[2] & mask + div / 2;//-------------结束像素处理------------------------}//单行处理结束
}//------------------------------------【方法十一】---------------------------------------------
//      说明:利用Mat Iterator_
//-------------------------------------------------------------------------------------------------
void colorReduce10(Mat &image, int div = 64) {//获取迭代器Mat_<Vec3b> cimage = image;Mat_<Vec3b>::iterator it = cimage.begin();Mat_<Vec3b>::iterator itend = cimage.end();for (; it != itend; it++) {//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] / div*div + div / 2;(*it)[1] = (*it)[1] / div*div + div / 2;(*it)[2] = (*it)[2] / div*div + div / 2;//-------------结束像素处理------------------------}
}//--------------------------------------【方法十二】--------------------------------------------
//      说明:利用动态地址计算配合at
//-------------------------------------------------------------------------------------------------
void colorReduce11(Mat &image, int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数for (int j = 0; j<nl; j++){for (int i = 0; i<nc; i++){//-------------开始处理每个像素-------------------image.at<Vec3b>(j, i)[0] = image.at<Vec3b>(j, i)[0] / div*div + div / 2;image.at<Vec3b>(j, i)[1] = image.at<Vec3b>(j, i)[1] / div*div + div / 2;image.at<Vec3b>(j, i)[2] = image.at<Vec3b>(j, i)[2] / div*div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                 }
}//----------------------------------【方法十三】-----------------------------------------------
//      说明:利用图像的输入与输出
//-------------------------------------------------------------------------------------------------
void colorReduce12(const Mat &image, //输入图像Mat &result,      // 输出图像int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数//准备好初始化后的Mat给输出图像result.create(image.rows, image.cols, image.type());//创建无像素填充的图像nc = nc*nl;nl = 1;  //单维数组int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g.比如div=16, mask= 0xF0for (int j = 0; j<nl; j++) {uchar* data = result.ptr<uchar>(j);const uchar* idata = image.ptr<uchar>(j);for (int i = 0; i<nc; i++) {//-------------开始处理每个像素-------------------*data++ = (*idata++)&mask + div / 2;*data++ = (*idata++)&mask + div / 2;*data++ = (*idata++)&mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//--------------------------------------【方法十四】-------------------------------------------
//      说明:利用操作符重载
//-------------------------------------------------------------------------------------------------
void colorReduce13(Mat &image, int div = 64) {int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0//进行色彩还原image = (image&Scalar(mask, mask, mask)) + Scalar(div / 2, div / 2, div / 2);
}//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main()
{int64 t[NTESTS], tinit;Mat image0;Mat image1;Mat image2;system("color 4F");image0 = imread("D://1.png");if (!image0.data) {cout <<  " could not image " << endl;getchar();return -1;
}//时间值设为0for (int i = 0; i<NTESTS; i++)t[i] = 0;// 多次重复测试int n = NITERATIONS;for (int k = 0; k<n; k++){cout << k << " of " << n << endl;image1 = imread("D://1.png");//【方法一】利用.ptr 和 []tinit = getTickCount();colorReduce0(image1);t[0] += getTickCount() - tinit;//【方法二】利用 .ptr 和 * ++ image1 = imread("D://1.png");tinit = getTickCount();colorReduce1(image1);t[1] += getTickCount() - tinit;//【方法三】利用.ptr 和 * ++ 以及模操作image1 = imread("D://1.png");tinit = getTickCount();colorReduce2(image1);t[2] += getTickCount() - tinit;//【方法四】 利用.ptr 和 * ++ 以及位操作image1 = imread("D://1.png");tinit = getTickCount();colorReduce3(image1);t[3] += getTickCount() - tinit;//【方法五】 利用指针的算术运算image1 = imread("D://1.png");tinit = getTickCount();colorReduce4(image1);t[4] += getTickCount() - tinit;//【方法六】利用 .ptr 和 * ++以及位运算、image.cols * image.channels()image1 = imread("D://1.png");tinit = getTickCount();colorReduce5(image1);t[5] += getTickCount() - tinit;//【方法七】利用.ptr 和 * ++ 以及位运算(continuous)image1 = imread("D://1.png");tinit = getTickCount();colorReduce6(image1);t[6] += getTickCount() - tinit;//【方法八】利用 .ptr 和 * ++ 以及位运算 (continuous+channels)image1 = imread("D://1.png");tinit = getTickCount();colorReduce7(image1);t[7] += getTickCount() - tinit;//【方法九】 利用Mat_ iteratorimage1 = imread("D://1.png");tinit = getTickCount();colorReduce8(image1);t[8] += getTickCount() - tinit;//【方法十】 利用Mat_ iterator以及位运算image1 = imread("D://1.png");tinit = getTickCount();colorReduce9(image1);t[9] += getTickCount() - tinit;//【方法十一】利用Mat Iterator_image1 = imread("D://1.png");tinit = getTickCount();colorReduce10(image1);t[10] += getTickCount() - tinit;//【方法十二】 利用动态地址计算配合atimage1 = imread("D://1.png");tinit = getTickCount();colorReduce11(image1);t[11] += getTickCount() - tinit;//【方法十三】 利用图像的输入与输出image1 = imread("D://1.png");tinit = getTickCount();Mat result;colorReduce12(image1, result);t[12] += getTickCount() - tinit;image2 = result;//【方法十四】 利用操作符重载image1 = imread("D://1.png");tinit = getTickCount();colorReduce13(image1);t[13] += getTickCount() - tinit;//------------------------------}//输出图像   imshow("原始图像", image0);imshow("结果", image2);imshow("图像结果", image1);// 输出平均执行时间cout << endl << "-------------------------------------------" << endl << endl;cout << "\n【方法一】利用.ptr 和 []的方法所用时间为 " << 1000.*t[0] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法二】利用 .ptr 和 * ++ 的方法所用时间为" << 1000.*t[1] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法三】利用.ptr 和 * ++ 以及模操作的方法所用时间为" << 1000.*t[2] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法四】利用.ptr 和 * ++ 以及位操作的方法所用时间为" << 1000.*t[3] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法五】利用指针算术运算的方法所用时间为" << 1000.*t[4] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法六】利用 .ptr 和 * ++以及位运算、channels()的方法所用时间为" << 1000.*t[5] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法七】利用.ptr 和 * ++ 以及位运算(continuous)的方法所用时间为" << 1000.*t[6] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法八】利用 .ptr 和 * ++ 以及位运算 (continuous+channels)的方法所用时间为" << 1000.*t[7] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法九】利用Mat_ iterator 的方法所用时间为" << 1000.*t[8] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十】利用Mat_ iterator以及位运算的方法所用时间为" << 1000.*t[9] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十一】利用Mat Iterator_的方法所用时间为" << 1000.*t[10] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十二】利用动态地址计算配合at 的方法所用时间为" << 1000.*t[11] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十三】利用图像的输入与输出的方法所用时间为" << 1000.*t[12] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十四】利用操作符重载的方法所用时间为" << 1000.*t[13] / getTickFrequency() / n << "ms" << endl;waitKey();return 0;
}

效果图

注意:第八种方法最快,利用 .ptr 和 * ++ 以及位运算 (continuous+channels)的方法所用时间为1.08502ms(以后就用第八种【以后复制粘贴第八种】,哈哈哈)

  1. 本人是抱着玩一玩的心态,学习opencv(其实深度学习没有外界说的这么高深,小嗷是白板,而且有工作在身并且于代码无关)
  2. 大家可以把我的数学水平想象成初中水平,毕竟小嗷既不是代码靠吃饭又不是靠数学吃饭,毕业N年
  3. 写文章主要是为了后人少走点弯路,多交点朋友,一起学习
  4. 如果有好的图像识别群拉我进去QQ:631821577
  5. 就我一个白板,最后还是成的,你们别怕,慢慢来把

分享可以无数次,转载成自己文章QQ邮箱通知一下,未经授权请勿转载。

  • 邮箱:631821577@qq.com
  • QQ群:736854977
  • 有什么疑问公众号提问,下班或者周六日回答,ths

10.马赛克原理之简单提高图像算法性能(颜色空间缩减和计时函数) --- OpenCV从零开始到图像(人脸 + 物体)识别系列相关推荐

  1. 23.代码简单实现模拟噪声(图像噪声/一、二阶矩/功率谱密度/at函数/rand函数)-- OpenCV从零开始到图像(人脸 + 物体)识别系列

    本文作者:小嗷 微信公众号:aoxiaoji 吹比QQ群:736854977 简书链接:https://www.jianshu.com/u/45da1fbce7d0 本文你会找到以下问题的答案: 图像 ...

  2. 利用 squid 反向代理提高网站性能

    本文在介绍 squid 反向代理的工作原理的基础上,指出反向代理技术在提高网站访问速度,增强网站可用性.安全性方面有很好的用途.作者在具体的实验环境下,利用 DNS 轮询和 Squid 反向代理技术, ...

  3. 数据库性能优化步骤_五个简单步骤即可提高数据库性能

    数据库性能优化步骤 2015年1月30日:根据读者的反馈意见,第4节"您是否有足够的数据库连接?" 已修改. 数据库访问是大多数应用程序的核心功能. 根据我们的经验,对于我们看到的 ...

  4. 10种简单的Java性能优化

    是否正打算优化hashCode()方法?是否想要绕开正则表达式?Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩展程序性能的技巧. 最近"全网域(Web Scale)" ...

  5. 无论新旧华为手机!简单调整这4个开关,就能一键提高手机性能

    华为手机一直都被很多人吐槽性能不好,使用起来不流畅等问题,但这跟处理器关系并不大,而是手机中的一些设置没调整. 其实只要调整这4个设置,无论新旧华为手机,都能轻松提高手机性能哦. 一.开启性能模式 不 ...

  6. 扩有mysql的磁盘_为提高MySQL性能而在磁盘IO方面的设置

    提起MySQL数据库在硬件方面的优化无非是CPU.内存和IO.下面我们着重梳理一下关于磁盘I/O方面的优化. 1.磁盘冗余阵列RAID RAID(Redundant Array of Inexpens ...

  7. redis提高oracle性能,redis性能分析与优化建议

    首先,并不是说redis是内存应用就完全没性能问题,用的不好,还是会出现各种状况,例如RDB频繁,碎片太多等. 性能分析 info信息: 在redis-cli进入登录界面后,输入info all,或者 ...

  8. 提高C++性能的编程技术笔记:引用计数+测试代码

    引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...

  9. 提高C++性能的编程技术笔记:内联+测试代码

    内联类似于宏,在调用方法内部展开被调用方法,以此来代替方法的调用.一般来说表达内联意图的方式有两种:一种是在定义方法时添加内联保留字的前缀:另一种是在类的头部声明中定义方法. 虽然内联方法的调用方式和 ...

最新文章

  1. 11JavaScript中的对象
  2. python语言怎么用-python语言中with as的用法使用详解
  3. LeetCode1262 可被三整除的最大和(动态规划)
  4. c语言贪吃蛇游戏完整代码
  5. Windows下载、安装、卸载Redis
  6. C/C++:Windows编程—调用DLL程序的2种方法
  7. SilverLight 初探一
  8. python错误和调试
  9. 《Python爬虫开发与项目实战》——第1章 回顾Python编程 1.1 安装Python
  10. WES 软件安装 及Bundel数据的下载
  11. 秒杀的倒计时按钮实现
  12. 基于C#实现的个人日程管理系统
  13. 2018年清华大学民商法学考研经验分享
  14. 图片边框变圆圈html,css如何设置边框的圆角样式?border-radius属性设置圆角样式(图 文)...
  15. ios开发之使用bundle来管理资源文件
  16. 深圳IT外包公司名单汇总
  17. 4399PK3366 拭目以待
  18. Adobe Acrobat XI Pro 2019安装教程
  19. java.lang.IllegalStateException: Did you forget to call 'public void setup(LocalActivityManager acti
  20. Struts2实现URL伪静态

热门文章

  1. 工业物联网与物联网区别_物联网节约用水,第1部分
  2. DSLR Video Tips: Cameras Lenses 数码单反相机视频提示:相机和镜头 Lynda课程中文字幕
  3. 里程计、推算定位与视觉里程计
  4. 计算机睡眠但不关闭网络,win7电脑睡眠不关闭网络技巧分享
  5. 【解决方案】AI智能+GPS定位,助力城市地摊管理的全面监控
  6. 科研资料|这才是毕业论文的正确打开方式!
  7. 【解决方案】云-边-端三体协同使用边缘端EasyNVR视频边缘计算网关搭建水上安全监管平台
  8. 视频编辑软件有哪些?介绍几种功能强大的编辑软件
  9. docx 图片预处理 Java_java使用poi给docx文档添加图片(官方例子)
  10. 企业电子招标采购系统源码之电子采购方案:构建高效智能数字化采购