在ARM-Linux下实现车牌识别(二)------车牌识别
你好!这里是风筝的博客,
欢迎和我一起交流。
之前说到,把车牌区域提前出来后,就可以着手识别程序了。先使用SVM判断是不是车牌。这里为了提高运行速度,板子资源有限,程序里我把svm训练部分注释掉了,假设每次都能找到车牌,实际使用时,还是要加上svm的。
然后对图像进行分割,我们的分类器只能对数字一个一个地识别,所以把每个数字分割出来,每个字符归一化为20*20的字符。
基本思想是先用findContours()函数把基本轮廓找出来,然后通过简单验证以确认是否为数字的轮廓。对于那些通过验证的轮廓,接下去会用boundingRect()找出它们的包围盒。
分割完后就可以进行识别了,字符识别使用ANN算法采用三层神经网络,识别需要用到一些xml文件,这些文件需要用分类器和大量样本做训练,提取他们的特征、,让机器去“学习”(利用训练好的XML文件去预测图像中车牌 ),我找的这三个xml数据集,说实话,不太好用,准确率一般般,有兴趣的可以自己训练。
完整程序如下,里面有详细注释了:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
#include <cvaux.h>
#include <stdio.h>
#include <opencv2/gpu/gpu.hpp>
#include <opencv2/ml/ml.hpp>using namespace cv;
using namespace std;//车牌宽高比为520/110=4.727272左右,误差不超过40%
//车牌高度范围在15~125之间,视摄像头距离而定(图像大小)
bool verifySizes_closeImg(const RotatedRect & candidate)
{float error = 0.4;//误差40%const float aspect = 4.7272;//44/14; //长宽比int min = 15*aspect*15;//20*aspect*20; //面积下限,最小区域int max = 125*aspect*125;//180*aspect*180; //面积上限,最大区域float rmin = aspect - aspect*error; //考虑误差后的最小长宽比float rmax = aspect + aspect*error; //考虑误差后的最大长宽比int area = candidate.size.height * candidate.size.width;//计算面积float r = (float)candidate.size.width/(float)candidate.size.height;//计算宽高比if(r <1)r = 1/r;if( (area < min || area > max) || (r< rmin || r > rmax) )//满足条件才认为是车牌候选区域return false;elsereturn true;
}void RgbConvToGray(const Mat& inputImage,Mat & outpuImage) //g = 0.3R+0.59G+0.11B
{outpuImage = Mat(inputImage.rows ,inputImage.cols ,CV_8UC1); for (int i = 0 ;i<inputImage.rows ;++ i){uchar *ptrGray = outpuImage.ptr<uchar>(i); const Vec3b * ptrRgb = inputImage.ptr<Vec3b>(i);for (int j = 0 ;j<inputImage.cols ;++ j){ptrGray[j] = 0.3*ptrRgb[j][2]+0.59*ptrRgb[j][1]+0.11*ptrRgb[j][0]; }}
}void normal_area(Mat &intputImg, vector<RotatedRect> &rects_optimal, vector <Mat>& output_area )
{float r,angle;for (int i = 0 ;i< rects_optimal.size() ; ++i){//旋转区域angle = rects_optimal[i].angle;r = (float)rects_optimal[i].size.width / (float) (float)rects_optimal[i].size.height;if(r<1)angle = 90 + angle;//旋转图像使其得到长大于高度图像。Mat rotmat = getRotationMatrix2D(rects_optimal[i].center , angle,1);//获得变形矩阵对象Mat img_rotated;warpAffine(intputImg ,img_rotated,rotmat, intputImg.size(),CV_INTER_CUBIC);imwrite("car_rotated.jpg",img_rotated);//得到旋转图像//裁剪图像Size rect_size = rects_optimal[i].size;if(r<1)swap(rect_size.width, rect_size.height); //交换高和宽Mat img_crop;getRectSubPix(img_rotated ,rect_size,rects_optimal[i].center , img_crop );//图像切割//用光照直方图调整所有裁剪得到的图像,使具有相同宽度和高度,适用于训练和分类Mat resultResized;//别人写的:/*resultResized.create(33,144,CV32FC1);resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC);resultResized.convertTo(resultResized, CV32FC1);resultResized = resultResized.reshape(1,1);*/resultResized.create(33,144,CV_8UC3);//CV32FC1????resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC);Mat grayResult;RgbConvToGray(resultResized ,grayResult);//blur(grayResult ,grayResult,Size(3,3));equalizeHist(grayResult,grayResult);output_area.push_back(grayResult);}
}bool char_verifySizes(const RotatedRect & candidate)
{float aspect = 45.0f/77.0f;//45.0f/90.0f;float width,height;if (candidate.size.width >=candidate.size.height){width = (float) candidate.size.height;height = (float) candidate.size.width;}else {width = (float) candidate.size.width;height = (float)candidate.size.height;}//这样确定是了高比宽要高float charAspect = (float) width/ (float)height;//宽高比float error = 0.35;//0.5;float minHeight = 15; //最小高度11float maxHeight = 28;//33; //最大高度33float minAspect = 0.15;//0.05; //考虑到数字1,最小长宽比为0.15float maxAspect = 1.0;if( charAspect > minAspect && charAspect <= 1.0&& height>= minHeight && height< maxHeight) //非0像素maxAspect长宽比、高度需满足条件return true;elsereturn false;
}void char_sort(vector <RotatedRect > & in_char ) //对字符区域进行排序
{vector <RotatedRect > out_char;const int length = 7; //7个字符int index[length] = {0,1,2,3,4,5,6};float centerX[length];for (int i=0;i < length ; ++ i){centerX[i] = in_char[i].center.x;}for (int j=0;j <length;j++) {for (int i=length-2;i >= j;i--)if (centerX[i] > centerX[i+1]){float t=centerX[i];centerX[i]=centerX[i+1];centerX[i+1]=t;int tt = index[i];index[i] = index[i+1];index[i+1] = tt;}}for(int i=0;i<length ;i++)out_char.push_back(in_char[(index[i])]);in_char.clear(); //清空in_charin_char = out_char; //将排序好的字符区域向量重新赋值给in_char
}void char_segment(const Mat & inputImg,vector <Mat>& dst_mat)//得到20*20的标准字符分割图像
{Mat img_threshold;threshold(inputImg ,img_threshold , 180,255 ,CV_THRESH_BINARY );//二值化//Mat element = getStructuringElement(MORPH_RECT ,Size(3 ,3)); //闭形态学的结构元素//morphologyEx(img_threshold ,img_threshold,CV_MOP_CLOSE,element); //形态学处理//imshow ("img_thresho00ld",img_threshold);//waitKey();Mat img_contours;img_threshold.copyTo(img_contours);if (!clearLiuDing(img_contours)){std::cout << "不是车牌" << endl;}else{//imshow("img_cda",img_contours);//waitKey();Mat result2;inputImg.copyTo(result2);vector < vector <Point> > contours;findContours(img_contours ,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);vector< vector <Point> > ::iterator itc = contours.begin();vector<RotatedRect> char_rects;drawContours(result2,contours,-1, Scalar(0,255,255), 1); while( itc != contours.end()){RotatedRect minArea = minAreaRect(Mat( *itc )); //返回每个轮廓的最小有界矩形区域Point2f vertices[4];minArea.points(vertices);if(!char_verifySizes(minArea)) //判断矩形轮廓是否符合要求{itc = contours.erase(itc);}else {++itc; char_rects.push_back(minArea); } }/*imshow("char1",char_rects[1]);imshow("char2",char_rects[2]);imshow("char3",char_rects[3]);imshow("char4",char_rects[4]);imshow("char5",char_rects[5]);imshow("char6",char_rects[6]);imshow("char7",char_rects[0]);waitKey();*/char_sort(char_rects); //对字符排序vector <Mat> char_mat;for (int i = 0; i<char_rects.size() ;i++ ){char_mat.push_back(Mat(img_threshold,char_rects[i].boundingRect()));}//imshow("char_mat1",char_mat[0]);//imshow("char_mat2",char_mat[1]);//imshow("char_mat3",char_mat[2]);//imshow("char_mat4",char_mat[3]);//imshow("char_mat5",char_mat[4]);//imshow("char_mat6",char_mat[5]);//imshow("char_mat7",char_mat[6]);//waitKey();Mat train_mat(2,3,CV_32FC1);int length ;dst_mat.resize(7);Point2f srcTri[3]; Point2f dstTri[3];for (int i = 0; i==0;i++){srcTri[0] = Point2f( 0,0 ); srcTri[1] = Point2f( char_mat[i].cols - 1, 0 ); srcTri[2] = Point2f( 0, char_mat[i].rows - 1 );length = char_mat[i].rows > char_mat[i].cols?char_mat[i].rows:char_mat[i].cols;dstTri[0] = Point2f( 0.0, 0.0 ); dstTri[1] = Point2f( length, 0.0 ); dstTri[2] = Point2f( 0.0, length ); train_mat = getAffineTransform( srcTri, dstTri );dst_mat[i]=Mat::zeros(length,length,char_mat[i].type()); warpAffine(char_mat[i],dst_mat[i],train_mat,dst_mat[i].size(),INTER_LINEAR,BORDER_CONSTANT,Scalar(0));//resize(dst_mat[i],dst_mat[i],Size(20,20),0,0,CV_INTER_CUBIC); //尺寸调整为20*20resize(dst_mat[i],dst_mat[i],Size(20,20));//每个字符归一化为20*20的字符}for (int i = 1; i< char_mat.size();++i){srcTri[0] = Point2f( 0,0 ); srcTri[1] = Point2f( char_mat[i].cols - 1, 0 ); srcTri[2] = Point2f( 0, char_mat[i].rows - 1 );length = char_mat[i].rows > char_mat[i].cols?char_mat[i].rows:char_mat[i].cols;dstTri[0] = Point2f( 0.0, 0.0 ); dstTri[1] = Point2f( length, 0.0 ); dstTri[2] = Point2f( 0.0, length ); train_mat = getAffineTransform( srcTri, dstTri );dst_mat[i]=Mat::zeros(length,length,char_mat[i].type()); warpAffine(char_mat[i],dst_mat[i],train_mat,dst_mat[i].size(),INTER_LINEAR,BORDER_CONSTANT,Scalar(0));//resize(dst_mat[i],dst_mat[i],Size(20,20),0,0,CV_INTER_CUBIC); //尺寸调整为20*20resize(dst_mat[i],dst_mat[i],Size(20,20));//每个字符归一化为20*20的字符}}
}void features(const Mat & in , Mat & out ,int sizeData)
{// 分别在水平方向和垂直方向上 创建累积直方图Mat vhist = projectHistogram(in , 1); //水平直方图Mat hhist = projectHistogram(in , 0); //垂直直方图// 低分辨率图像// 低分辨率图像中的每一个像素都将被保存在特征矩阵中Mat lowData;resize(in , lowData ,Size(sizeData ,sizeData ));//特征矩阵的列数int numCols = vhist.cols + hhist.cols + lowData.cols * lowData.cols;out = Mat::zeros(1, numCols , CV_32F);// 向特征矩阵赋值int j = 0;for (int i =0 ;i<vhist.cols ; ++i)// 首先把水平方向累积直方图的值,存到特征矩阵中{out.at<float>(j) = vhist.at<float>(i);j++;}for (int i=0 ; i < hhist.cols ;++i)// 然后把竖直方向累积直方图的值,存到特征矩阵中{out.at<float>(j) = hhist.at<float>(i);}for(int x =0 ;x<lowData.rows ;++x)// 最后把低分辨率图像的像素值,存到特征矩阵中{for (int y =0 ;y < lowData.cols ;++ y){out.at<float>(j) = (float)lowData.at<unsigned char>(x,y);j++;}}
}void ann_train(CvANN_MLP &ann ,int numCharacters, int nlayers, string str)//http://blog.csdn.net/yiqiudream/article/details/51712497
{Mat trainData ,classes;FileStorage fs;fs.open(str, FileStorage::READ);//str是文件名字fs["TrainingData"] >>trainData;fs["classes"] >>classes;//CvANN_MLP bp; //Set up BPNetwork's parameters //CvANN_MLP_TrainParams params; //params.train_method=CvANN_MLP_TrainParams::BACKPROP; //params.bp_dw_scale=0.1; //params.bp_moment_scale=0.1; Mat layerSizes(1,3,CV_32SC1);layerSizes.at<int>( 0 ) = trainData.cols;layerSizes.at<int>( 1 ) = nlayers; //隐藏神经元数,可设为3layerSizes.at<int>( 2 ) = numCharacters; //样本类数为34//layerSizes.at<int>( 3 ) = numCharacters ;ann.create(layerSizes , CvANN_MLP::SIGMOID_SYM ); //初始化annMat trainClasses;trainClasses.create(trainData.rows , numCharacters ,CV_32FC1);for (int i =0;i< trainData.rows; i++){for (int k=0 ; k< trainClasses.cols ; k++ ){if ( k == (int)classes.at<uchar> (i)){trainClasses.at<float>(i,k) = 1 ;}elsetrainClasses.at<float>(i,k) = 0; } }Mat weights(1 , trainData.rows , CV_32FC1 ,Scalar::all(1) );ann.train( trainData ,trainClasses , weights);
}void svm_train(CvSVM & svmClassifier)
{FileStorage fs;fs.open("SVM.xml" , FileStorage::READ);Mat SVM_TrainningData;Mat SVM_Classes; fs["TrainingData"] >>SVM_TrainningData;fs["classes"] >>SVM_Classes;CvSVMParams SVM_params;SVM_params.kernel_type = CvSVM::LINEAR;svmClassifier.train(SVM_TrainningData,SVM_Classes ,Mat(),Mat(),SVM_params); //SVM训练模型fs.release();
}int main(int argc, char* argv[])
{Mat img_input= imread("./car.jpg");//加载图片if(img_input.empty())//如果读入图像失败{cout << "Can not load image" << endl;return -1;}Mat hsvImg ;cvtColor(img_input,hsvImg,CV_BGR2HSV);//RGB模型转换成HSV模型imwrite("car_hsv.jpg",hsvImg);//看下hsv效果vector <Mat> hsvSplit;split(hsvImg,hsvSplit);//将图像的各个通道分离equalizeHist(hsvSplit[2],hsvSplit[2]);//直方图均衡化,提高图像的质量merge(hsvSplit,hsvImg);//将分离的多个单通道合成一幅多通道图像imwrite("car_hsv1.jpg",hsvImg);//看下处理效果const int min_blue =100;//最小蓝车区域const int max_blue =240;//最大蓝车区域int avg_h = (min_blue+max_blue)/2;int channels = hsvImg.channels();int nRows = hsvImg.rows;//图像数据列需要考虑通道数的影响;int nCols = hsvImg.cols * channels;if (hsvImg.isContinuous())//连续存储的数据,按一行处理{nCols *= nRows;nRows = 1;}int i, j;unsigned char* p;const float minref_sv = 64; //参考的S V的值const float max_sv = 255; // S V 的最大值for (i = 0; i < nRows; ++i)//根据蓝色在HSV在的区域每个通道的取值范围将此作为阈值,提取出图片中蓝色部分作为备选区域{p = hsvImg.ptr<uchar>(i);//有效提高了车牌和车色颜色在不相差较大的情况下的识别率for (j = 0; j < nCols; j += 3)//致命问题:蓝色的车和蓝色的牌照?{int H = int(p[j]); //0-180int S = int(p[j + 1]); //0-255int V = int(p[j + 2]); //0-255bool colorMatched = false;if (H > min_blue && H < max_blue){int Hdiff = 0;float Hdiff_p = float(Hdiff) / 40;float min_sv = 0;if (H > avg_h){Hdiff = H - avg_h;} else{Hdiff = avg_h - H;}min_sv = minref_sv - minref_sv / 2 * (1 - Hdiff_p);if ((S > 70&& S < 255) &&(V > 70 && V < 255))colorMatched = true;}if (colorMatched == true) {p[j] = 0; p[j + 1] = 0; p[j + 2] = 255;}else {p[j] = 0; p[j + 1] = 0; p[j + 2] = 0;}}}Mat src_grey;Mat img_threshold;vector<Mat> hsvSplit_done;split(hsvImg, hsvSplit_done);src_grey = hsvSplit_done[2];//提取黑色分量imwrite("car_hsvSplit.jpg",src_grey);//查看分离通道出来的车牌vector <RotatedRect> rects;Mat element = getStructuringElement(MORPH_RECT ,Size(17 ,3)); //闭形态学的结构元素morphologyEx(src_grey ,img_threshold,CV_MOP_CLOSE,element); //闭运算,先膨胀后腐蚀,连通近邻区域(填补白色区域的间隙)morphologyEx(img_threshold,img_threshold,MORPH_OPEN,element);//形态学处理imwrite("car_morphology.jpg",img_threshold);//查看thresholdvector< vector <Point> > contours;//寻找车牌区域的轮廓findContours(img_threshold ,contours,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//只检测外轮廓。存储所以轮廓点//绘制轮廓/*for(int find=0; find < contours.size(); find++)drawContours(img_threshold, contours, find, Scalar(255), 2);imwrite("car_contours.jpg",img_threshold);//查看轮廓*///对候选的轮廓进行进一步筛选vector< vector <Point> > ::iterator itc = contours.begin();while( itc != contours.end()){RotatedRect mr = minAreaRect(Mat( *itc )); //返回每个轮廓的最小有界矩形区域if(!verifySizes_closeImg(mr)) //判断矩形轮廓是否符合要求{itc = contours.erase(itc);}else {rects.push_back(mr);++itc;} }vector <Mat> output_area;normal_area(img_input ,rects,output_area); //获得144*33的候选车牌区域output_areaimwrite("car_area.jpg",output_area[0]);//得到候选区域,这里可能会获得多个候选区域,最好使用svm训练一下//(二)添加如下://CvSVM svmClassifier;//为了运行速度,我就把这里注释掉了,这样会降低准确度//svm_train(svmClassifier); //使用SVM对正负样本进行训练,为了运行速度,我就把这里注释掉了,这样会降低准确度vector<Mat> plates_svm; //需要把候选车牌区域output_area图像中每个像素点作为一行特征向量,后进行预测for(int i=0;i< output_area.size(); ++i)//实际情况下应该加上SVM训练,我这里是学习测试{cout << "output " << i << endl;Mat img = output_area[i];Mat p = img.reshape(1,1);p.convertTo(p,CV_32FC1);//int response = (int)svmClassifier.predict( p );//为了运行速度,我就把这里注释掉了,这样会降低准确度//if (response == 1)//为了运行速度,我就把这里注释掉了,这样会降低准确度plates_svm.push_back(output_area[i]); //保存预测结果}//从SVM预测获取车牌区域分割得到字符区域vector <Mat> char_seg;char_segment(plates_svm[0],char_seg);//对车牌区域中字符进行分割imwrite("char0.jpg",char_seg[0]);//显示七个字符imwrite("char1.jpg",char_seg[1]);imwrite("char2.jpg",char_seg[2]);imwrite("char3.jpg",char_seg[3]);imwrite("char4.jpg",char_seg[4]);imwrite("char5.jpg",char_seg[5]);imwrite("char6.jpg",char_seg[6]);//获得7个字符矩阵的相应特征矩阵vector <Mat> char_feature;char_feature.resize(7);for (int i =0;i<char_seg.size() ;++ i)features(char_seg[i], char_feature[i],5);//神经网络训练CvANN_MLP ann_classify;//对字母和数字ann_train(ann_classify,34,20,"ann_xml.xml");//输入层经元数(离线训练数据集的行数),隐藏层的神经元数,文件名字CvANN_MLP ann_classify1;//对第一个汉字进行分类建模ann_train(ann_classify1,3,20,"ann_xml_character.xml");//字符预测vector<int> char_result;//classify(ann_classify,char_feature,char_result);char_result.resize(char_feature.size());for (int i=0;i<char_feature.size(); ++i){if (i==0)//对汉字{Mat output(1 ,34, CV_32FC1); //1*34矩阵 //ann.predict(char_feature[i] ,output);ann_classify1.predict(char_feature[i],output);//对每个字符运用ANN.predict函数得出1*类别数的数据组(数据组中是记录这个字符跟每个类别的“相似度”)Point maxLoc;double maxVal;minMaxLoc(output , 0 ,&maxVal , 0 ,&maxLoc);//找出最大概率的类别char_result[i] = maxLoc.x;}else//对字母和数字{Mat output(1 ,34, CV_32FC1); //1*34矩阵//ann.predict(char_feature[i] ,output);ann_classify.predict(char_feature[i],output);//预测Point maxLoc;double maxVal;minMaxLoc(output , 0 ,&maxVal , 0 ,&maxLoc);char_result[i] = maxLoc.x;}}if(plates_svm.size() != 0) {cout << "create a image" << endl;imwrite("car_opencv_final.jpg",output_area[0]); //正确预测的话,就只有一个结果plates_svm[0] }else{std::cout<<"定位失败";return -1;}cout<<"该车牌后7位为:";char s[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'};//现在添加了京cout<<'\n'; string chinese[]={"湘","鄂","粤","甘","贵","桂","黑","沪","冀","津","京","吉","辽","鲁","蒙","闵","宁","青","琼","陕","苏","晋","皖","湘","浙","豫","渝","粤","云"};for (int w=0;w<char_result.size(); w++) //第一位是汉字,这里没实现对汉字的预测{ if (w==0){cout<<chinese[char_result[w]];//可以对汉字京的识别cout<<'\t';}else{cout<< s[char_result[w]];cout<<'\t';}}return 0;
}
源代码和xml文件下载:https://download.csdn.net/download/guet_kite/10930196
代码大部分都是抄网上一篇文章的,文章地址我找不到了…
不过给出几个参考链接,可以看看里面的。
参考:
[1]:使用opencv的SVM和神经网络实现车牌识别
[2]:OpenCV自学笔记17. 基于SVM和神经网络的车牌识别
[3]:OpenCV实现车牌识别,OCR分割,ANN神经网络
在ARM-Linux下实现车牌识别(二)------车牌识别相关推荐
- ARM Linux下UPnP使用
ARM Linux下UPnP使用 一.UPnP简介 UPnP(Universal Plug and Play)技术是一种屏蔽各种数字设备的硬件和操作系统的通信协议.它是一种数字网络中间件技术, ...
- linux pfn,ARM Linux下的page和pfn之间转换的宏。
ARM Linux下的page和pfn之间转换的宏如下: 1)page_to_pfn 2)pfn_to_page 这两个宏依赖于内核编译时,选择的内存模型.在include/asm-generic/m ...
- linux-arm下如何开启tftp传输,arm linux 下移植busybox 的tftp
(1)进入busybox目录,make menuconfig ,然后在networking中勾选tftp项跟tftpd项. (2)配置/etc/inetd.conf 中关于tftp的选项(此部未验证, ...
- [2021]Linux下C语言qrencode二维码生成库的基本使用和ARM开发板移植
文章目录 一.前言 二.准备所用到的环境以及版本信息 1.Ubuntu和内核版本 2.gcc和g++版本 3.交叉编译gcc和g++版本 4.开发板信息 三.开发环境编译&安装qrencode ...
- arm linux下交叉编译valgrind工具进行内存泄露检测和性能分析
C/C++等底层语言在提供强大功能及性能的同时,其灵活的内存访问也带来了各种纠结的问题.如果crash的地方正是内存使用错误的地方,说明你人品好.如果crash的地方内存明显不是consistent的 ...
- PL2303在ARM Linux下驱动的问题及解决方法
问题描述:项目需要用ARM板驱动金笛wavecom GSM模块发短信,该GSM模块为USB接口,内部采用PL2303HX芯片转为RS232接口实现AT指令协议. 将GSM模块插入ARM板的USB口,发 ...
- easypr arm linux,arm linux下交叉編譯EasyPR中文車牌識別系統開發(一)
EasyPR中文車牌識別系統開發(一),我主要介紹如何使用開源的EasyPR中文車牌識別系統,當然后面我會介紹訓練機器學習 SVM 支持向量機和 ANN 人工神經網絡模型在車牌識別的應用. 目錄: 一 ...
- 你知道不同U盘在ARM+Linux下的读写速率吗?
优秀的产品离不开完善的测试,即使一个简单的USB接口也要确保稳定性及兼容性.不同的U盘在ARM+Linux板卡下的兼容性.速率怎么样呢?本文将为大家提供测试参考数据及详细测试步骤! 1. 测试准备 主 ...
- arm linux下看门狗应用,arm linux watchdog 看门狗
目前手上有个项目需要设计看门狗,是arm+CPLD 方式.由于对看门狗要求很高,打算做一个双看门狗,arm CPLD互相为 对方的看门狗.理论上CPLD是不需要看门狗的,还是这么去设计了.接下来对看门 ...
- 4G通信模块在嵌入式ARM Linux下的应用
4G通信模块是连接物与物的重要载体,是终端设备接入物联网的核心部件之一.4G通信模块把频率接收器和信号增幅器等部件全都整合在一起,实现了一体化.随着工业发展,嵌入式设备接入网络的需求日益增多, ...
最新文章
- matlab图像处理——分水岭法
- conda pip安装在哪里_TensorFlow 2.0 安装指南
- JUC多线程:创建线程的四种方式
- idea 启动tomcat 工程_如何在IDEA中创建web项目并且部署到Tomcat中
- python 艺术照片滤镜_Python实现PS滤镜Fish lens图像扭曲效果示例
- mysql join 与 cross join 效率_浅析Mysql Join语法以及性能优化
- 做生意,没亏过钱,自然也没赚过钱
- AbortController 中止一个或多个Web请求
- 用php解决钱币组合问题,关于若干数组组合的问题 PHP
- 网络计算机自动显示,怎么设置电脑断网后自动报警提醒?
- 使用Silvaco设计构建NMOS晶体管、PNP、NPN双极型晶体管并提取各项工艺及器件参数:半导体器件和工艺模拟
- android 汉字拼音排序,Android实现中文按拼音排序方法
- 虚拟手游服务器,自己搭建手机游戏服务器
- 全新原装 SD3337C SOP8 丝印HXN 升压DC/DC转换器恒流白光LED驱动
- 北京信息科技大学第十二届程序设计竞赛暨ACM选拔赛
- 6096. 咒语和药水的成功对数
- 计算机毕业设计springbootiMeli在线彩妆店铺
- Java简单知识点小结
- officemix安装 0x80091007 哈希数值不正确
- Html form表单验证