fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】

前言

做图像处理的第一步是读图,在C++中读图的方式很多,常用的是采用OpenCV读图,但是OpenCV只能读取二维的图像,无法读取三维的图像。除此之外,还可以采用ITK、VTK读取图像,但是这两种工具封装的太好,使用起来并不灵活。这两种工具底层都是调用libtiff库读取图像,所以我们也可以直接利用libtiff读取图像。

今天就讲讲如何利用libtiff读取图像,并且用OpenCV显示其中的一帧。

如果您觉得这篇博文对您有用,请轻轻点赞,谢谢

软件工具:VS2013+libtiff+Win7(X64)

工程配置

由于我的libtiff库是64位的,所以创建的是X64的项目。然后将libtiff和OpenCV的包含目录添加到常规项。

然后将库目录输入到链接器的常规项

最后,将静态库名添加到链接器的输入项

工程配置就ok了。

代码

为了讲解方便,在此直接给出图像读入和写出的代码;

读入方式1

void open_Fun1(const char* file,vector<Mat> &buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);     //------获取通道数//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);//---------------------申请单帧图像所需的内存空间;uint32* count = new uint32[height*width];   //uint32* count = new uint32[stripSize]; for (int s = 0; s < nTotalFrame; s++){//---------------------建立单张画布;Mat MatImage(height, width, CV_8UC1, Scalar::all(0));TIFFSetDirectory(tif, s);       //-------选中第s帧TIFFReadRGBAImage(tif, width, height, count, 0);       //将第s帧的内容传递到count中;默认参数选择是0,所以是逆序读入的。可以使用ORIENTATION_TOPLEFT作为参数,从左上角开始uint32* rowPoint2Src = count + (height - 1)*width;     //构建一个指向最后一行的第一个元素。注意这里,是从最后一行开始读入的for (int i = 0; i <height; i++){uint32* colPoint2Src = rowPoint2Src;for (int j = 0; j <width; j++){MatImage.at<uchar>(i, j) = (uchar)TIFFGetG(*colPoint2Src);      //按照像素点读取colPoint2Src++;}rowPoint2Src -= width;                              }buffer.push_back(MatImage);MatImage.release();}TIFFClose(tif);delete[] count;size[0] = width;size[1] = height;size[2] = nTotalFrame;
}

代码分析

1. 打开图像

TIFF* TIFFOpen(const char*, const char*);

TIFFOpen( )函数有两个参数,第一个是图像的目录以及文件名,第二个是打开方式。这与一般的文件打开函数是一样的,就不多说了。

2. 获取图像参数

int width, height;//-------------获取单帧图像的长高
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);     //------获取通道数//------------ 获取图片帧数
int nTotalFrame = TIFFNumberOfDirectories(tif);
printf("width: %d\n", width);
printf("Slice: %d\n", nTotalFrame);
printf("height: %d\n", height);
//---------------获取每一帧的像素点数目
int stripSize = TIFFStripSize(tif);

如注释中所写,使用TIFFGetField()函数可以获得图像的许多参数,包括单帧图像的长、宽、图像位深、通道数、方向等。

使用TIFFNumberOfDirectories()可以获得图像的帧数,TIFFStripSize()可以获得每一帧的像素点数目。

3. 获取一层图像所以像素点的值

TIFFSetDirectory(tif, s);       //-------选中第s帧TIFFReadRGBAImage(tif, width, height, count, 0);       //将第s帧的内容传递到count中;默认参数选择是0,所以是逆序读入的。可以使用ORIENTATION_TOPLEFT作为参数,从左上角开始

读取文件时TIFFSetDirectory()寒素可以用从0开始的序号选择任意一帧图像,TIFFReadDirectory()和TIFFWriteDirectory()可以用于顺序读写每一帧,只需要一个while循环即可 。这里的代码先选中图像的第s帧。然后按RGBA图像的方式读入,注意这种方式只能读入8bit的图像,无法读入16bit图像。因为RGBA图像的所有参数都是在0~255之间的,这样构成了一个32bit的RGBA像素的图像。

4. 获取每个像素点的值

uint32* rowPoint2Src = count + (height - 1)*width;     //构建一个指向最后一行的第一个元素。注意这里,是从最后一行开始读入的for (int i = 0; i <height; i++)
{uint32* colPoint2Src = rowPoint2Src;for (int j = 0; j <width; j++){MatImage.at<uchar>(i, j) = (uchar)TIFFGetG(*colPoint2Src);      //按照像素点读取colPoint2Src++;}rowPoint2Src -= width;
}

因为前面获取每一帧采用的是TIFFReadRGBAImage()的方法,所以这里采用TIFFGetG()获得像素点的值。

转到TIFFGetG() 的定义可以看到如下内容。这里除了不能使用TIFFGetA()之外,其他三种宏获得的像素值是一样的。

#define TIFFGetR(abgr) ((abgr) & 0xff)
#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)
#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)
#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)

这样遍历所有的像素点,就能获得所有的像素值。

5. 关闭图像

TIFFClose();这里也不必多说,在所有操作都执行完毕后,关闭图像。

读入方式2

很显然,刚刚的读入方式,只能读入8bit的图像,那么16位的图像如何读入呢?话不多说,shangdaim

代码

void open_Fun2(const char* file, uint16 **buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);*buffer = new uint16[nTotalFrame*stripSize];int N_size = 0;for (int s = 0; s < nTotalFrame; s++){for (int row = 0; row < height; row++){TIFFReadScanline(tif, (&(*buffer)[N_size] + row*int(width)), row);      //---按行读取}N_size += width*height;TIFFReadDirectory(tif);}TIFFClose(tif);size[0] = width;size[1] = height;size[2] = nTotalFrame;
}

代码分析

前面参数获取的过程与读入方式1中完全一样,就不作分析了。

获取每个点像素值

int N_size = 0;
for (int s = 0; s < nTotalFrame; s++)
{for (int row = 0; row < height; row++){TIFFReadScanline(tif, (&(*buffer)[N_size] + row*int(width)), row);      //---按行读取}N_size += width*height;TIFFReadDirectory(tif);}

这里的图像读入方式是使用TIFFReadScanline()读入图像,libtiff提供的最简单的接口是scanline方式的接口,用于读取条状或块状的图像,这种方式只能用于读写非压缩格式图像。函数为TIFFReadScanline()和TIFFWriteScanline()。

读入方式3

这里的读入方式3与读入方式1方法其实是一样的。

代码

void open_Fun3(const char* file, vector<Mat> &buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);//---------------------申请单帧图像所需的内存空间;uint32* slice = new uint32[height*width];//uint32* count = new uint32[stripSize]; //---------------------建立单张画布;for (int z = 0; z<int(nTotalFrame); ++z){Mat MatImage(height, width, CV_32FC1, Scalar::all(0));TIFFReadRGBAImageOriented(tif, width, height, slice, ORIENTATION_TOPLEFT);        //先用slice指向某一帧像素,原理与Fun1()类似int ss = 0;for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){MatImage.at<float>(i, j) = TIFFGetR(slice[ss]);                          //从一帧中的每个点获取像素值ss++;}}TIFFReadDirectory(tif);buffer.push_back(MatImage);MatImage.release();}TIFFClose(tif);delete[] slice;size[0] = width;size[1] = height;size[2] = nTotalFrame;}

代码分析

与方法一中唯一的不同就是获取每一帧图像的代码不一样,原理是一样的,就不多加赘述。

除了上面的三种方法之外,libtiff 还有提供了一种读取可以处理压缩或非压缩图像的方法,Strip-oriented。这里也不多讲了,有兴趣的朋友可以自己去调研。

图像写出

有读就有写,这是自然,由于篇幅原因,只提供一种图像写出的方法,应该够用了,毕竟了解了原理,过程只是调用API而已。

代码

void saveTiff(const char *path,uint16 *buffer,int *size)
{int width = size[0];int height = size[1];int slice = size[2];TIFF* out = TIFFOpen(path, "w");if (out){int N_size = 0;size_t nCur = 0;//UChar den = (sizeof(T) == 1) ? 1 : 4;do{TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);TIFFSetField(out, TIFFTAG_PAGENUMBER, slice);TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32)width);TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32)height);//TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, 2);/*TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.0f);TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0f);*/TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);// TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16);    //根据图像位深填不同的值TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, height);for (int m = 0; m < height; m++){TIFFWriteScanline(out, &buffer[N_size + width*m], m, 0);}//TIFFWriteEncodedStrip(out, 0, &buffer[N_size], width * height);      //另一种写入方法++nCur;N_size = N_size + width*height;} while (TIFFWriteDirectory(out) && nCur < slice);TIFFClose(out);cout << "save over";}
}

代码分析

1. TIFFOpen()

使用TIFFOpen()打开写出的文件,此时第二个参数为”w“;

2. 对图像标签赋值

TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
TIFFSetField(out, TIFFTAG_PAGENUMBER, slice);
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32)width);
TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32)height);
//TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, 2);
/*TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.0f);
TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0f);*/
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
//
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16);    //根据图像位深填不同的值
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, height);

保存TIFF图像时,设置标签是必不可少的过程,其中主要包括压缩方式、图像位深、单帧大小、帧数等信息。

3. 图像赋值

for (int m = 0; m < height; m++)
{TIFFWriteScanline(out, &buffer[N_size + width*m], m, 0);
}

图像写出的方法使用的是之前提到过的TIFFWriteScanline()按行写出函数,函数第一个参数是输出图像的指针,第二个是存放了图像像素值的数组,后面的就是第多少行,以及显出顺序。

运行结果

结果中输出了图像大小信息,以及三位图像的某一帧。

全部代码

事先说明,这里使用vector或者使用数组存放图像跟图像本身没有关系,只是我自己的编写程序的习惯问题。

//-------opentiff.h
#ifndef OPENTIFF_H
#define OPENTIFF_H#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>using namespace std;
using namespace cv;void open_Fun1(const char*, vector<Mat> &buffer,int *size);
void open_Fun2(const char*, uint16 **buffer,int *size);
void open_Fun3(const char*, vector<Mat> &buffer,int *size);
void saveTiff(const char *path, uint16 *buffer, int *size);#endif
//-------------test.cpp
//-----------读写三维Tiff
//----------不用先生,2018.03.30
#include <iostream>
#include <vector>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include "tiff.h"
#include "tiffio.h"
#include "opentiff.h"
using namespace std;
using namespace cv;void main(){const char* filename8bit = "C:\\Users\\most_pan\\Desktop\\testpic\\test.tif";const char* filename16bit = "C:\\Users\\most_pan\\Desktop\\testpic\\test16bit.tif";int *sizes = new int[3];//------------------调用Fun1()读图/*vector<Mat> Three_tiff;open_Fun1(filename8bit, Three_tiff,sizes);Mat OutImage;normalize(Three_tiff[99], OutImage, 1, 0.00, NORM_MINMAX);imshow("test", OutImage);cout << (float)Three_tiff[99].at<float>(50, 20);imwrite("C:/Users/most_pan/Desktop/testss.jpg", Three_tiff[99]);waitKey(0);OutImage.release();*///------------------调用Fun2()读图//uint16 *Three_tiff_buffer;//open_Fun2(filename16bit, &Three_tiff_buffer,sizes);//const char* filename16bitsave = "C:\\Users\\most_pan\\Desktop\\testpic\\test16bitsave.tif";//saveTiff(filename16bitsave, Three_tiff_buffer, sizes);展示一层//int width = sizes[0];//int height = sizes[1];//Mat MatImage(height, width, CV_32FC1, Scalar::all(0));//int s = 0;//for (int i = 0; i < height; i++)//{// for (int j = 0; j < width; j++)// {//     MatImage.at<float>(i, j) = Three_tiff_buffer[s];//       s++;//    }//}//Mat OutImage;//normalize(MatImage, OutImage, 1, 0.00, NORM_MINMAX);//imshow("test", OutImage);//waitKey(0);//MatImage.release();//OutImage.release();//delete []Three_tiff_buffer;//delete[] sizes;//------------------调用Fun3()读图vector<Mat> Three_tiff;open_Fun3(filename8bit, Three_tiff,sizes);Mat OutImage;normalize(Three_tiff[99], OutImage, 1, 0.00, NORM_MINMAX);imshow("test", OutImage);waitKey(0);cout << (float)Three_tiff[99].at<float>(50, 20);imwrite("C:/Users/most_pan/Desktop/testss.jpg", Three_tiff[99]);OutImage.release();system("pause");return;
}void open_Fun1(const char* file,vector<Mat> &buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);     //------获取通道数//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);//---------------------申请单帧图像所需的内存空间;uint32* count = new uint32[height*width];   //uint32* count = new uint32[stripSize]; for (int s = 0; s < nTotalFrame; s++){//---------------------建立单张画布;Mat MatImage(height, width, CV_8UC1, Scalar::all(0));TIFFSetDirectory(tif, s);       //-------选中第s帧TIFFReadRGBAImage(tif, width, height, count, 0);       //将第s帧的内容传递到count中;默认参数选择是0,所以是逆序读入的。可以使用ORIENTATION_TOPLEFT作为参数,从左上角开始uint32* rowPoint2Src = count + (height - 1)*width;     //构建一个指向最后一行的第一个元素。注意这里,是从最后一行开始读入的for (int i = 0; i <height; i++){uint32* colPoint2Src = rowPoint2Src;for (int j = 0; j <width; j++){MatImage.at<uchar>(i, j) = (uchar)TIFFGetG(*colPoint2Src);      //按照像素点读取colPoint2Src++;}rowPoint2Src -= width;                              }buffer.push_back(MatImage);MatImage.release();}TIFFClose(tif);delete[] count;size[0] = width;size[1] = height;size[2] = nTotalFrame;
}//--------------------------读取16位图像
void open_Fun2(const char* file, uint16 **buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);*buffer = new uint16[nTotalFrame*stripSize];int N_size = 0;for (int s = 0; s < nTotalFrame; s++){for (int row = 0; row < height; row++){TIFFReadScanline(tif, (&(*buffer)[N_size] + row*int(width)), row);      //---按行读取}N_size += width*height;  TIFFReadDirectory(tif);}TIFFClose(tif);size[0] = width;size[1] = height;size[2] = nTotalFrame;
}
//-------------------读取8位图像
void open_Fun3(const char* file, vector<Mat> &buffer,int *size)
{TIFF *tif = TIFFOpen(file, "r");      //使用TIFFOpen函数以只读形式打开图像。if (tif == nullptr){cout << "读入图像路径错误,请重新确认";return;}int width, height;//-------------获取单帧图像的长高TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);//TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &channel);//------------ 获取图片帧数int nTotalFrame = TIFFNumberOfDirectories(tif);printf("width: %d\n", width);printf("Slice: %d\n", nTotalFrame);printf("height: %d\n", height);//---------------获取每一帧的像素点数目int stripSize = TIFFStripSize(tif);//---------------------申请单帧图像所需的内存空间;uint32* slice = new uint32[height*width];//uint32* count = new uint32[stripSize]; //---------------------建立单张画布;for (int z = 0; z<int(nTotalFrame); ++z){Mat MatImage(height, width, CV_32FC1, Scalar::all(0));TIFFReadRGBAImageOriented(tif, width, height, slice, ORIENTATION_TOPLEFT);        //先用slice指向某一帧像素,原理与Fun1()类似int ss = 0;for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){MatImage.at<float>(i, j) = TIFFGetR(slice[ss]);                          //从一帧中的每个点获取像素值ss++;}}TIFFReadDirectory(tif);buffer.push_back(MatImage);MatImage.release();}TIFFClose(tif);delete[] slice;size[0] = width;size[1] = height;size[2] = nTotalFrame;}void saveTiff(const char *path,uint16 *buffer,int *size)
{int width = size[0];int height = size[1];int slice = size[2];TIFF* out = TIFFOpen(path, "w");if (out){int N_size = 0;size_t nCur = 0;do{TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);TIFFSetField(out, TIFFTAG_PAGENUMBER, slice);TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32)width);TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32)height);//TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, 2);/*TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.0f);TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0f);*/TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);// TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16);    //根据图像位深填不同的值TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, height);for (int m = 0; m < height; m++){TIFFWriteScanline(out, &buffer[N_size + width*m], m, 0);}//TIFFWriteEncodedStrip(out, 0, &buffer[N_size], width * height);      //另一种写入方法++nCur;N_size = N_size + width*height;} while (TIFFWriteDirectory(out) && nCur < slice);TIFFClose(out);cout << "save over";}
}

最后

自己当初编译libtiff的时候花费了不少时间,这里给大家提供我所使用的64位程序的库函数,libtiff(X64),我象征性的收取2个积分,如果确实没积分,可以评论找我,我也会给你提供库文件的。

【图像处理】libtiff读写三维TIFF图像(附详细代码)相关推荐

  1. 玩转树莓派---详解树莓派的系统烧录,基础使用及基于树莓派制作手势控制的小车(附详细代码及演示效果)

    目录 一.写在前面 二.系统实现: Author:qyan.li Date:2022.6.10 Topic:详解树莓派的使用及基于树莓派制作手势控制的小车 Reference:如何给树莓派安装操作系统 ...

  2. Web前端:HTML最强总结 附详细代码

    Web前端基础: Web前端:HTML最强总结 附详细代码 Web前端:CSS最强总结 附详细代码 Web前端:JavaScript最强总结 附详细代码 Web前端工具: Web前端: JQuery最 ...

  3. Opencv+Python学习记录9:掩膜(掩码)的使用(内附详细代码)

    一,基本概念 OpenCV中的很多函数都会指定一个掩模,也被称为掩码,例如: 计算结果=cv2.add(参数1,参数2,掩模) 当使用掩模参数时,操作只会在掩模值为非空的像素点上执行,并将其他像素点的 ...

  4. Web前端:Bootstrap最强总结 附详细代码 (带常用案例!)

    Web前端基础: Web前端:HTML最强总结 附详细代码 Web前端:CSS最强总结 附详细代码 Web前端:JavaScript最强总结 附详细代码 Web前端工具: Web前端: JQuery最 ...

  5. php实现飘窗,JS实现网站图片飘窗效果,JavaScript悬浮广告(附详细代码)

    原标题:JS实现网站图片飘窗效果,JavaScript悬浮广告(附详细代码) JS实现网站图片飘窗效果,Java悬浮广告,郑州SEO提供以下代码,仅供参考: 飘窗效果-丁光辉博客(www.dinggu ...

  6. c语言二分法_14个经典C语言算法你就不看一眼?(附详细代码)

    今天,给大家讲一讲,单片机常用的14个C语言算法(附详细代码)哟! 一.计数.求和.求阶乘等简单算法 此类问题都要使用循环,要注意根据问题确定循环变量的初值.终值或结束条件,更要注意用来表示计数.和. ...

  7. 用html实现抽奖大转盘,【项目实战】用CSS实现一个抽奖转盘(附详细代码+思路)...

    原标题:[项目实战]用CSS实现一个抽奖转盘(附详细代码+思路) 效果 基本是用CSS实现的,没有用图片,加一丢丢JS. 完全没有考虑兼容性. 首先画一个转盘 < htmllang= " ...

  8. hfss和python_利用Python与HFSS联合仿真设计一个微带天线(附详细代码)

    原标题:利用Python与HFSS联合仿真设计一个微带天线(附详细代码) 我们知道HFSS是一款电磁仿真商用软件,用其进行天线的设计十分方便.而该软件也预留了可以运行脚本的接口,使用者可以使用脚本对软 ...

  9. Web前端:JavaScript最强总结 附详细代码 (带常用案例!)

    Web前端基础: Web前端:HTML最强总结 附详细代码 Web前端:CSS最强总结 附详细代码 Web前端:JavaScript最强总结 附详细代码 Web前端工具: Web前端: JQuery最 ...

最新文章

  1. 使用JAVA开发微信公众平台(一)——环境搭建与开发接入
  2. vue全家桶项目搭建(vue-cli 2.9.6+vue-router+vuex+axios)
  3. 【Java源码分析】LinkedHashSet和HashSet源码分析
  4. 开发日记-20190605 关键词 读书笔记《鸟哥的Linux私房菜-基础学习篇》
  5. Programming Computer Vision with Python (学习笔记四)
  6. java 去除干扰_【Selenium-WebDriver实战篇】Java丨验证码图片去除干扰像素,方便验证码的识别(转)...
  7. android如何获取默认的桌面程序
  8. 线程池的简单创建和实现
  9. fedora 用安装 DVD 建立本地 yum 源
  10. 服务器时间延迟,如何处理从服务器延迟响应时间'力逼近'
  11. Python笔记-获取某贴吧页面所有的贴吧id
  12. oracle无法减小列长度,中国港湾扩展表单分配时调整字段后保存时报错,无法正常维护表单定义...
  13. Linux怎么修改用户密码
  14. 【SSDP 协议介绍】
  15. C语言读取文件所有内容
  16. 服务器appcrash的问题怎么修复,APPCRASH问题如何解决
  17. Java连接打印机打印二维码
  18. 天天向商为什么更名,更名为稿定设计之后有什么变化?
  19. 宝华计算机维修,唐山市路北区宝华计算机维修服务
  20. 图片怎么压缩?这些方法值得收藏

热门文章

  1. TypeScript入门教程 之 类/抽象类/构造器/Getter/Setter
  2. Oracle性能调优方法
  3. 快速安装Docker图形化管理平台ShipYard
  4. 52个有效方法(1) - 了解Objective-C语言的起源
  5. react-native构建基本页面5---调用拍照摄像头
  6. .net core3.1 下由Autofac接管IOC
  7. window系统盘瘦身(开发)
  8. 初识函数式编程(Functional Programming,FP)
  9. 【Linux】Aria2 一键安装管理脚本 BT\PT一键安装包
  10. charles源码分析