OpenCV图片校正

OpenCV图片校正

  • 背景
  • 几种校正方法
  • 1.傅里叶变换 + 霍夫变换+ 直线 + 角度 + 旋转
  • 3.四点透视 + 角度 + 旋转
  • 4.检测矩形轮廓 + 角度 + 旋转
  • 参考

背景

遇到偏的图片想要校正成水平或者垂直的。

几种校正方法

对于倾斜的图片通过矫正可以得到水平的图片。一般有如下几种基于opencv的组合方式进行图片矫正。

  • 1、傅里叶变换 + 霍夫变换+ 直线 + 角度 + 旋转
  • 2、边缘检测 + 霍夫变换 + 直线+角度 + 旋转
  • 3、四点透视 + 角度 + 旋转
  • 4、检测矩形轮廓 + 角度 + 旋转

1.傅里叶变换 + 霍夫变换+ 直线 + 角度 + 旋转

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>using namespace cv;
using namespace std;// 二值化阈值
#define GRAY_THRESH 150// 直线上点的个数
#define HOUGH_VOTE 50int main(int argc, char **argv)
{//Read a single-channel imageconst char* filename = "31.png";Mat srcImg = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);if (srcImg.empty())return -1;imshow("source", srcImg);Point center(srcImg.cols / 2, srcImg.rows / 2);//Expand image to an optimal size, for faster processing speed//Set widths of borders in four directions//If borderType==BORDER_CONSTANT, fill the borders with (0,0,0)Mat padded;int opWidth = getOptimalDFTSize(srcImg.rows);int opHeight = getOptimalDFTSize(srcImg.cols);copyMakeBorder(srcImg, padded, 0, opWidth - srcImg.rows, 0, opHeight - srcImg.cols, BORDER_CONSTANT, Scalar::all(0));Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };Mat comImg;//Merge into a double-channel imagemerge(planes, 2, comImg);//Use the same image as input and output,//so that the results can fit in Mat welldft(comImg, comImg);//Compute the magnitude//planes[0]=Re(DFT(I)), planes[1]=Im(DFT(I))//magnitude=sqrt(Re^2+Im^2)split(comImg, planes);magnitude(planes[0], planes[1], planes[0]);//Switch to logarithmic scale, for better visual results//M2=log(1+M1)Mat magMat = planes[0];magMat += Scalar::all(1);log(magMat, magMat);//Crop the spectrum//Width and height of magMat should be even, so that they can be divided by 2//-2 is 11111110 in binary system, operator & make sure width and height are always evenmagMat = magMat(Rect(0, 0, magMat.cols & -2, magMat.rows & -2));//Rearrange the quadrants of Fourier image,//so that the origin is at the center of image,//and move the high frequency to the cornersint cx = magMat.cols / 2;int cy = magMat.rows / 2;Mat q0(magMat, Rect(0, 0, cx, cy));Mat q1(magMat, Rect(0, cy, cx, cy));Mat q2(magMat, Rect(cx, cy, cx, cy));Mat q3(magMat, Rect(cx, 0, cx, cy));Mat tmp;q0.copyTo(tmp);q2.copyTo(q0);tmp.copyTo(q2);q1.copyTo(tmp);q3.copyTo(q1);tmp.copyTo(q3);//Normalize the magnitude to [0,1], then to[0,255]normalize(magMat, magMat, 0, 1, CV_MINMAX);Mat magImg(magMat.size(), CV_8UC1);magMat.convertTo(magImg, CV_8UC1, 255, 0);imshow("magnitude", magImg);//imwrite("imageText_mag.jpg",magImg);//Turn into binary imagethreshold(magImg, magImg, GRAY_THRESH, 255, CV_THRESH_BINARY);imshow("mag_binary", magImg);//imwrite("imageText_bin.jpg",magImg);//Find lines with Hough Transformationvector<Vec2f> lines;float pi180 = (float)CV_PI / 180;Mat linImg(magImg.size(), CV_8UC3);HoughLines(magImg, lines, 1, pi180, HOUGH_VOTE, 0, 0);int numLines = lines.size();for (int l = 0; l<numLines; l++){float rho = lines[l][0], theta = lines[l][1];Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));line(linImg, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0);}imshow("lines", linImg);//imwrite("imageText_line.jpg",linImg);if (lines.size() == 3){cout << "found three angels:" << endl;cout << lines[0][1] * 180 / CV_PI << endl << lines[1][1] * 180 / CV_PI << endl << lines[2][1] * 180 / CV_PI << endl << endl;}//Find the proper angel from the three found angelsfloat angel = 0;float piThresh = (float)CV_PI / 90;float pi2 = CV_PI / 2;for (int l = 0; l<numLines; l++){float theta = lines[l][1];if (abs(theta) < piThresh || abs(theta - pi2) < piThresh)continue;else{angel = theta;break;}}//Calculate the rotation angel//The image has to be square,//so that the rotation angel can be calculate rightangel = angel<pi2 ? angel : angel - CV_PI;if (angel != pi2){float angelT = srcImg.rows*tan(angel) / srcImg.cols;angel = atan(angelT);}float angelD = angel * 180 / (float)CV_PI;cout << "the rotation angel to be applied:" << endl << angelD << endl << endl;//Rotate the image to recoverMat rotMat = getRotationMatrix2D(center, angelD, 1.0);Mat dstImg = Mat::ones(srcImg.size(), CV_8UC3);warpAffine(srcImg, dstImg, rotMat, srcImg.size(), 1, 0, Scalar(255, 255, 255));imshow("result", dstImg);//imwrite("imageText_D.jpg",dstImg);waitKey(0);return 0;
}

opencv4x

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs/legacy/constants_c.h> 
#include <iostream>using namespace cv;
using namespace std;// 二值化阈值
#define GRAY_THRESH 150// 直线上点的个数
#define HOUGH_VOTE 50int main(int argc, char **argv)
{//Read a single-channel imageconst char* filename = argv[1];Mat srcImg = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);if (srcImg.empty())return -1;imshow("source", srcImg);Point center(srcImg.cols / 2, srcImg.rows / 2);//Expand image to an optimal size, for faster processing speed//Set widths of borders in four directions//If borderType==BORDER_CONSTANT, fill the borders with (0,0,0)Mat padded;int opWidth = getOptimalDFTSize(srcImg.rows);int opHeight = getOptimalDFTSize(srcImg.cols);copyMakeBorder(srcImg, padded, 0, opWidth - srcImg.rows, 0, opHeight - srcImg.cols, BORDER_CONSTANT, Scalar::all(0));Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };Mat comImg;//Merge into a double-channel imagemerge(planes, 2, comImg);//Use the same image as input and output,//so that the results can fit in Mat welldft(comImg, comImg);//Compute the magnitude//planes[0]=Re(DFT(I)), planes[1]=Im(DFT(I))//magnitude=sqrt(Re^2+Im^2)split(comImg, planes);magnitude(planes[0], planes[1], planes[0]);//Switch to logarithmic scale, for better visual results//M2=log(1+M1)Mat magMat = planes[0];magMat += Scalar::all(1);log(magMat, magMat);//Crop the spectrum//Width and height of magMat should be even, so that they can be divided by 2//-2 is 11111110 in binary system, operator & make sure width and height are always evenmagMat = magMat(Rect(0, 0, magMat.cols & -2, magMat.rows & -2));//Rearrange the quadrants of Fourier image,//so that the origin is at the center of image,//and move the high frequency to the cornersint cx = magMat.cols / 2;int cy = magMat.rows / 2;Mat q0(magMat, Rect(0, 0, cx, cy));Mat q1(magMat, Rect(0, cy, cx, cy));Mat q2(magMat, Rect(cx, cy, cx, cy));Mat q3(magMat, Rect(cx, 0, cx, cy));Mat tmp;q0.copyTo(tmp);q2.copyTo(q0);tmp.copyTo(q2);q1.copyTo(tmp);q3.copyTo(q1);tmp.copyTo(q3);//Normalize the magnitude to [0,1], then to[0,255]//normalize(magMat, magMat, 0, 1, CV_MINMAX);normalize(magMat, magMat, 0, 1, NORM_MINMAX);Mat magImg(magMat.size(), CV_8UC1);magMat.convertTo(magImg, CV_8UC1, 255, 0);imshow("magnitude", magImg);//imwrite("imageText_mag.jpg",magImg);//Turn into binary imagethreshold(magImg, magImg, GRAY_THRESH, 255, cv::THRESH_BINARY);imshow("mag_binary", magImg);//imwrite("imageText_bin.jpg",magImg);//Find lines with Hough Transformationvector<Vec2f> lines;float pi180 = (float)CV_PI / 180;Mat linImg(magImg.size(), CV_8UC3);HoughLines(magImg, lines, 1, pi180, HOUGH_VOTE, 0, 0);int numLines = lines.size();for (int l = 0; l<numLines; l++){float rho = lines[l][0], theta = lines[l][1];Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));line(linImg, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0);}imshow("lines", linImg);//imwrite("imageText_line.jpg",linImg);if (lines.size() == 3){cout << "found three angels:" << endl;cout << lines[0][1] * 180 / CV_PI << endl << lines[1][1] * 180 / CV_PI << endl << lines[2][1] * 180 / CV_PI << endl << endl;}//Find the proper angel from the three found angelsfloat angel = 0;float piThresh = (float)CV_PI / 90;float pi2 = CV_PI / 2;for (int l = 0; l<numLines; l++){float theta = lines[l][1];if (abs(theta) < piThresh || abs(theta - pi2) < piThresh)continue;else{angel = theta;break;}}//Calculate the rotation angel//The image has to be square,//so that the rotation angel can be calculate rightangel = angel<pi2 ? angel : angel - CV_PI;if (angel != pi2){float angelT = srcImg.rows*tan(angel) / srcImg.cols;angel = atan(angelT);}//float angelD = angel * 180 / (float)CV_PI;float angelD = angel * 180 / (float)CV_PI;cout << "the rotation angel to be applied: "<< angelD << endl << endl;//Rotate the image to recoverMat rotMat = getRotationMatrix2D(center, angelD, 1.0);Mat dstImg = Mat::ones(srcImg.size(), CV_8UC3);warpAffine(srcImg, dstImg, rotMat, srcImg.size(), 1, 0, Scalar(255, 255, 255));imshow("result", dstImg);imwrite("imageText_D.jpg",dstImg);waitKey(0);return 0;
}

CMakeLists.txt

project( main )
cmake_minimum_required(VERSION 3.10) 
#添加头文件路径
include_directories(/usr/local/include /usr/local/include/opencv4 /usr/local/include/opencv4/opencv2)
#添加库文件路径
link_directories(/usr/local/lib)add_executable(main test.cpp)
target_link_libraries( main -lopencv_core  -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs)

在这里插入图片描述
在这里插入图片描述

3.四点透视 + 角度 + 旋转

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;// 直线上点的个数
#define HOUGH_VOTE 50//度数转换
double DegreeTrans(double theta)
{double res = theta / CV_PI * 180;return res;
}//逆时针旋转图像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{//旋转中心为图像中心    Point2f center;center.x = float(src.cols / 2.0);center.y = float(src.rows / 2.0);int length = 0;length = sqrt(src.cols*src.cols + src.rows*src.rows);//计算二维旋转的仿射变换矩阵  Mat M = getRotationMatrix2D(center, degree, 1);warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);cvtColor(midImage, dstImage, CV_GRAY2BGR);//通过霍夫变换检测直线vector<Vec2f> lines;HoughLines(midImage, lines, 1, CV_PI / 180, HOUGH_VOTE);//第5个参数就是阈值,阈值越大,检测精度越高//cout << lines.size() << endl;//由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢//所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。float sum = 0;//依次画出每条线段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0];float theta = lines[i][1];Point pt1, pt2;//cout << theta << endl;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));//只选角度最小的作为旋转角度sum += theta;line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色imshow("直线探测效果图", dstImage);}float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好cout << "average theta:" << average << endl;double angle = DegreeTrans(average) - 90;rotateImage(dstImage, dst, angle);//imshow("直线探测效果图2", dstImage);return angle;
}void ImageRecify(const char* pInFileName, const char* pOutFileName)
{double degree;Mat src = imread(pInFileName);imshow("原始图", src);Mat dst;//倾斜角度矫正degree = CalcDegree(src, dst);rotateImage(src, dst, degree);cout << "angle:" << degree << endl;imshow("旋转调整后", dst);Mat resulyImage = dst(Rect(0, 0, dst.cols, 500)); //根据先验知识,估计好文本的长宽,再裁剪下来imshow("裁剪之后", resulyImage);imwrite("recified.jpg", resulyImage);
}int main()
{ImageRecify("31.png", "FinalImage.jpg");waitKey();return 0;
}

opencv4.x

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;// 直线上点的个数
#define HOUGH_VOTE 50//度数转换
double DegreeTrans(double theta)
{double res = theta / CV_PI * 180;return res;
}//逆时针旋转图像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{//旋转中心为图像中心    Point2f center;center.x = float(src.cols / 2.0);center.y = float(src.rows / 2.0);int length = 0;length = sqrt(src.cols*src.cols + src.rows*src.rows);//计算二维旋转的仿射变换矩阵  Mat M = getRotationMatrix2D(center, degree, 1);warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);cvtColor(midImage, dstImage, COLOR_GRAY2BGR);//通过霍夫变换检测直线vector<Vec2f> lines;HoughLines(midImage, lines, 1, CV_PI / 180, HOUGH_VOTE);//第5个参数就是阈值,阈值越大,检测精度越高//cout << lines.size() << endl;//由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢//所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。float sum = 0;//依次画出每条线段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0];float theta = lines[i][1];Point pt1, pt2;//cout << theta << endl;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));//只选角度最小的作为旋转角度sum += theta;line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色imshow("直线探测效果图", dstImage);}float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好cout << "average theta:" << average << endl;double angle = DegreeTrans(average) - 90;rotateImage(dstImage, dst, angle);//imshow("直线探测效果图2", dstImage);return angle;
}void ImageRecify(const char* pInFileName, const char* pOutFileName)
{double degree;Mat src = imread(pInFileName);imshow("原始图", src);Mat dst;//倾斜角度矫正degree = CalcDegree(src, dst);rotateImage(src, dst, degree);cout << "angle:" << degree << endl;imshow("旋转调整后", dst);Mat resulyImage = dst(Rect(0, 0, dst.cols, 1000)); //根据先验知识,估计好文本的长宽,再裁剪下来imshow("裁剪之后", resulyImage);imwrite("recified.jpg", resulyImage);
}int main()
{ImageRecify("test.jpg", "FinalImage.jpg");waitKey();return 0;
}

4.检测矩形轮廓 + 角度 + 旋转

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#include <algorithm>bool x_sort(const Point2f & m1, const Point2f & m2)
{return m1.x < m2.x;
}//第一个参数:输入图片名称;第二个参数:输出图片名称
void GetContoursPic(const char* pSrcFileName, const char* pDstFileName)
{Mat srcImg = imread(pSrcFileName);imshow("原始图", srcImg);Mat gray, binImg;//灰度化cvtColor(srcImg, gray, COLOR_RGB2GRAY);imshow("灰度图", gray);//二值化threshold(gray, binImg, 150, 200, CV_THRESH_BINARY);imshow("二值化", binImg);vector<Point>  contours;vector<vector<Point> > f_contours;//注意第5个参数为CV_RETR_EXTERNAL,只检索外框  findContours(binImg, f_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓int max_area = 0;int index;for (int i = 0; i < f_contours.size(); i++){double tmparea = fabs(contourArea(f_contours[i]));if (tmparea > max_area){index = i;max_area = tmparea;}}contours = f_contours[index];CvBox2D rect = minAreaRect(Mat(contours));float angle = rect.angle;cout << "before angle : " << angle << endl;if (angle < -45)angle = (90 + angle);elseangle = -angle;cout << "after angle : " << angle << endl;//新建一个感兴趣的区域图,大小跟原图一样大  Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3RoiSrcImg.setTo(0); //颜色都设置为黑色  //imshow("新建的ROI", RoiSrcImg);//对得到的轮廓填充一下  drawContours(binImg, f_contours, 0, Scalar(255), CV_FILLED);//抠图到RoiSrcImgsrcImg.copyTo(RoiSrcImg, gray);//再显示一下看看,除了感兴趣的区域,其他部分都是黑色的了  namedWindow("RoiSrcImg", 1);imshow("RoiSrcImg", RoiSrcImg);//创建一个旋转后的图像  Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);RatationedImg.setTo(0);//对RoiSrcImg进行旋转  Point2f center = rect.center;  //中心点  Mat M2 = getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 imshow("旋转之后", RatationedImg);
}void main()
{GetContoursPic("34.png", "FinalImage.jpg");waitKey();
}

opencv4.x

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <opencv2/imgproc/types_c.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>using namespace cv;
using namespace std;
#include <algorithm>bool x_sort(const Point2f & m1, const Point2f & m2)
{return m1.x < m2.x;
}//第一个参数:输入图片名称;第二个参数:输出图片名称
void GetContoursPic(const char* pSrcFileName, const char* pDstFileName)
{Mat srcImg = imread(pSrcFileName);imshow("原始图", srcImg);Mat gray, binImg;//灰度化cvtColor(srcImg, gray, COLOR_RGB2GRAY);imshow("灰度图", gray);//二值化threshold(gray, binImg, 150, 200, cv::THRESH_BINARY);imshow("二值化", binImg);vector<Point>  contours;vector<vector<Point> > f_contours;//注意第5个参数为CV_RETR_EXTERNAL,只检索外框  findContours(binImg, f_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓int max_area = 0;int index;for (int i = 0; i < f_contours.size(); i++){double tmparea = fabs(contourArea(f_contours[i]));if (tmparea > max_area){index = i;max_area = tmparea;}}contours = f_contours[index];RotatedRect rect = minAreaRect(Mat(contours));float angle = rect.angle;cout << "before angle : " << angle << endl;if (angle < -45)angle = (90 + angle);elseangle = -angle;cout << "after angle : " << angle << endl;//新建一个感兴趣的区域图,大小跟原图一样大  Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3RoiSrcImg.setTo(0); //颜色都设置为黑色  //imshow("新建的ROI", RoiSrcImg);//对得到的轮廓填充一下  drawContours(binImg, f_contours, 0, Scalar(255), cv::FILLED);//抠图到RoiSrcImgsrcImg.copyTo(RoiSrcImg, gray);//再显示一下看看,除了感兴趣的区域,其他部分都是黑色的了  namedWindow("RoiSrcImg", 1);imshow("RoiSrcImg", RoiSrcImg);//创建一个旋转后的图像  Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);RatationedImg.setTo(0);//对RoiSrcImg进行旋转  Point2f center = rect.center;  //中心点  Mat M2 = getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 imshow("旋转之后", RatationedImg);imwrite("recified.jpg", RatationedImg);
}int main()
{GetContoursPic("test.jpg", "FinalImage.jpg");waitKey();return 0;
}

参考

  • 榴莲小怪兽 opencv-图片矫正
  • OpenCV利用透视变换矫正图像

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/99284.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab 检测点云中指定尺寸的矩形平面

目录 一、概述1、算法概述2、主要函数二、代码示例三、结果展示四、参数解析输入参数名称-值对应参数输出参数五、参考链接一、概述 1、算法概述 detectRectangularPlanePoints:检测点云中指定尺寸的矩形平面 <

解决爬虫上下行传输效率问题的实用指南

嗨&#xff0c;大家好&#xff01;作为一名专业的爬虫程序员&#xff0c;我们经常会面临上下行传输效率低下的问题。在处理大量数据时&#xff0c;如果传输效率不高&#xff0c;可能会导致爬虫任务速度慢&#xff0c;甚至中断。今天&#xff0c;我将和大家分享一些解决爬虫上下…

Mysql的索引详解

零. 索引类型概述 1. 实际开发中使用的索引种类 主键索引唯一索引普通索引联合索引全文索引空间索引 2. 索引的格式类型 BTree类型Hash类型FullText类型&#xff08;全文索引)RTree类型&#xff08;空间索引) MySQL 的索引方法&#xff0c;主要包括 BTREE 和 HASH。 顾名思…

部门来了个测试开发,听说是00后,上来一顿操作给我看呆了...

公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司实习半年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍&#xff01…

不含数字的webshell绕过

异或操作原理 1.首先我们得了解一下异或操作的原理 在php中&#xff0c;异或操作是两个二进制数相同时&#xff0c;异或(相同)为0&#xff0c;不同为1 举个例子 A的ASCII值是65&#xff0c;对应的二进制值是0100 0001 的ASCII值是96&#xff0c;对应的二进制值是 0110 000…

【STM32+ESP8266上云连载①】给ESP8266烧录AT固件

文章目录 一、给NodeMCU烧录固件1.1硬件准备1.2软件准备1.3AT固件下载1.4配置设置1.5开始烧录 二、给ESP8266-01S烧录固件2.1硬件准备2.2AT固件下载2.3连线2.4烧录配置 三、给ESP-12E/F/S单片烧录固件四、指令测试4.1HTTP测试4.2MQTT测试 我在使用ESP8266的时候遇到了一些问题&…

语法篇--XML数据传输格式

一、XML概述 1.1简介 XML&#xff0c;全称为Extensible Markup Language&#xff0c;即可扩展标记语言&#xff0c;是一种用于存储和传输数据的文本格式。它是由W3C&#xff08;万维网联盟&#xff09;推荐的标准&#xff0c;广泛应用于各种系统中&#xff0c;如Web服务、数据…

jmeter-results-detail-report_new.xsl文件设置dateReport

<!-- Defined parameters (overrideable) <td bgcolor"#ff00ff"> --> <xsl:param name"showData" select"y"/> <xsl:param name"titleReport" select"测试报告"/> <xsl:param name&…

【UniApp开发小程序】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】

文章目录 界面效果界面实现工具js页面日期格式化 后端收藏ControllerServicemapper 评论ControllerServiceMapper 商品Controller 阅读Service 界面效果 【说明】 界面中商品的图片来源于闲鱼&#xff0c;若侵权请联系删除 【商品详情】 【评论】 界面实现 工具js 该工…

Spring中循环依赖解决方案

循环依赖 循环依赖是Spring框架中常见的问题之一&#xff0c;当两个或多个类相互引用对方时&#xff0c;就会出现循环依赖的情况。这种情况下&#xff0c;Spring框架无法确定哪个类应该先实例化和初始化&#xff0c;从而导致异常。常见的解决方法有&#xff1a;构造函数注入、s…

SpringBoot+微信小程序奶茶在线点单小程序系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码 一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBoot微信小程序框架开发的奶茶在线点单小程序系统。首先&#xff0c;这是一个前后端分离的项目&#xff…

基于springboot+vue的博物馆藏品平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Harvard transformer NLP 模型 openNMT 简介入门

项目网址&#xff1a; OpenNMT - Open-Source Neural Machine Translation logo&#xff1a; 一&#xff0c;从应用的层面先跑通 Harvard transformer GitHub - harvardnlp/annotated-transformer: An annotated implementation of the Transformer paper. ​git clone https…

Android Studio导入项目需要做的一些配置

点击项目结构 选择本地安装的SDK、NDK目录 选择java版本 重新加载项目 Clean Project Rebuild Project 选择要构建的版本 可选debug和release 打包apk安装包 打包完成&#xff0c;就可以安装到安卓手机了

matlab 计算点云平均密度

目录 一、算法原理二、代码实现三、结果展示四、C++版计算结果本文由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 采样设备不同、设备距离场景远近不同,会使点云密度产生差异。现有的对点云密度的估算方法有基…

「UG/NX」Block UI 体收集器BodyCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

js中的正则表达式(一)

目录 1.什么是正则表达式 2.正则表达式在JavaScript中的使用场景: 3.正则表达式的语法&#xff1a; 1.什么是正则表达式 正则表达式(Regular Expression&#xff09;是用于匹配字符串中字符组合的模式。在JavaScript中&#xff0c;正则表达式也是对象通常用来查找、替换那些符…

TCP/IP协议组

TCP/IP通信协议是目前最完整、使用最广泛的通信协议。它的魅力在于可使不同硬件结构、不同操作系统的计算机相互通信。TCP/IP协议既可用于广域网&#xff0c;也可用于局域网&#xff0c;它是Internet/Intranet的基石。TCP/IP通信协议事实上是一组协议。 TCP/IP协议可分为5层也可…

阿里云ECS服务器企业级和共享型介绍_企业级常见问题解答FAQ

阿里云企业级服务器是什么&#xff1f;企业级和共享型有什么区别&#xff1f;企业级服务器具有独享且稳定的计算、存储、网络资源&#xff0c;如ECS计算型c6、通用型g8等都是企业级实例&#xff0c;阿里云百科分享什么是企业级云服务器、企业级实例的优势、企业级和共享型云服务…

限制 el-input 输入 emoji

1. 电脑如何输入 emoji 表情 ? 快捷键 win; 或 win. 2. 代码实现 <template><el-input v-model"input" placeholder"请输入内容" input"inputChange"></el-input> </template><script> export default {name: D…