Tutorial introductorio de OpenCV (muy detallado) desde la entrada de base cero hasta la competencia, basta con leer este artículo

Introducción a los conceptos básicos de OpenCV [Lenguaje C++]

    • Capítulo 1 leer imagen/video/cámara
      • leer imagen del archivo
      • leer video del archivo
      • leer cámara web
    • Capítulo 2 funciones básicas
    • Capítulo 3 Ajuste y recorte
    • Capítulo 4 Dibujar formas y texto
    • Transformación de la perspectiva del capítulo 5
    • Capítulo 6 Detección de color
    • Capítulo 7 Detección de forma/contorno
    • Capítulo 8 Detección de rostros
    • Proyecto1 Pintor Virtual
    • Escaneo de documentos de Project2
    • Detección de matrículas de Project3
  1. Paquete de instalación de OpenCV3.4.6 (incluida la contribución): https://pan.baidu.com/s/1KBD-fAO63p0s5ANYa5XcEQ código de extracción: p7j0
  2. recursos recurso: https://pan.baidu.com/s/1nkQ6iVV7IeeP4gTXvM_DyQ código de extracción: ypvt

Capítulo 1 leer imagen/video/cámara

leer imagen del archivo

módulo Función
imgcódecs Lectura y escritura de archivos de imagen
imgproc Procesamiento de imágenes
altagui GUI de alto nivel
  • Mat cv::imread(const String &filename, int flags = IMREAD_COLOR)

Carga una imagen desde un archivo . La función imreadcarga una imagen del archivo especificado y la devuelve. Si la imagen no se puede leer (debido a la falta de archivos, permisos incorrectos, formato no compatible o no válido), la función devuelve una matriz vacía ( Mat::data==NULL). En el caso de imágenes en color, los canales de la imagen decodificada se almacenarán en orden BGR.

  • void cv::imshow(cosnst String &winnanme, InputArray mat)

Muestra la imagen en la ventana especificada . Esta función debe ir seguida de cv::waitKeyla función que muestra la imagen durante los milisegundos especificados. De lo contrario, no mostrará la imagen. Por ejemplo, waitKey(0)la ventana se mostrará infinitamente hasta que se presione cualquier tecla (adecuado para la visualización de imágenes). waitKey(25)Se mostrará un cuadro durante 25 ms, después de lo cual la pantalla se apagará automáticamente. (si lo pone en bucle para leer el video, mostrará el video cuadro por cuadro)

  • int cv::waitKey(int delay = 0)

Espere a que se presione una tecla . La función waitKeyespera indefinidamente un evento de pulsación de tecla ( delay≤0while ) o se retrasa en milisegundos cuando es positivo. Dado que el sistema operativo tiene un tiempo mínimo entre el cambio de subprocesos, la función no espera exactamente los milisegundos de retraso, espera al menos los milisegundos de retraso, dependiendo de qué más se esté ejecutando en su computadora en ese momento. Devuelve el código de la tecla que se presionó o -1 si no se presiona ninguna tecla antes de que haya transcurrido el tiempo especificado.

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	string path = "Resources/test.png";
	Mat img = imread(path);
	imshow("Image", img);
	waitKey(0); //显示图片不会一闪而过

	return 0;
}

cv1

leer video del archivo

Para capturar video, se debe crear un objeto VideoCapture. Su argumento puede ser el nombre de un archivo de video o un índice de dispositivo. Constructor de clase y función miembro
en OpenCV3.4.6VideoCapture

  • cv::VideoCapture::VideoCapture()
  • cv::VideoCapture::VideoCapture(const String &filename)
  • cv::VideoCapture::VideoCapture(const String &filename, int apiPreference)
  • cv::VideoCapture::VideoCapture(int index)
  • cv::VideoCapture::VideoCapture(int index, int apiPreference)

Abra un archivo de video o un dispositivo de captura o una secuencia de video IP para la captura de video .

  • virtual bool cv::VideoCapture::isOpened() const

Devuelve verdadero si se ha inicializado la captura de vídeo . Este método devuelve verdadero si una llamada anterior al VideoCaptureconstructor VideoCapture::open()tuvo éxito.

  • virtual bool cv::VideoCapture::read(OutputArray image)

Tome, decodifique y devuelva el siguiente cuadro de video .

  • virtual double cv::VideoCapture::get(int proId) const

Devuelve la VideoCapturepropiedad especificada .

  • virtual double cv::VideoCapture::set(int proId, double value)

VideoCaptureEstablecer una propiedad en .

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	string path = "Resources/test_video.mp4";
	VideoCapture cap(path); //视频捕捉对象
	Mat img;
	while (true) {

		cap.read(img);

		imshow("Image", img);
		waitKey(1);
	}
	return 0;
}

leer cámara web

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	VideoCapture cap(0);
	Mat img;

	while (true) {

		cap.read(img);

		imshow("Image", img);
		waitKey(1);
	}

	return 0;
}

Capítulo 2 funciones básicas

  • void cv::cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0)

Convierte una imagen de un espacio de color a otro . Esta función convierte una imagen de entrada de un espacio de color a otro. En el caso de convertir desde un espacio de color RGB, el orden de los canales (RGB o BGR) debe especificarse explícitamente. man Tenga en cuenta que el formato de color predeterminado en OpenCV a menudo se llama RGB, pero en realidad es BGR (Byte invertido). Por lo tanto, el primer byte en una imagen de color estándar (24 bits) será el componente azul de 8 bits, el segundo byte será verde y el tercer byte será rojo. Luego, los bytes cuarto, quinto y sexto serán el segundo píxel (azul, luego verde, luego rojo), y así sucesivamente.

  • void cv::GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, doube sigmaY = 0, int borderType = BORDER_DEFAULT)

Desenfoca la imagen utilizando un filtro gaussiano . Esta función convoluciona la imagen de origen con el núcleo gaussiano especificado.

  • void cv::Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false)

Encuentra bordes en una imagen usando el algoritmo de Canny .

  • Mat cv::getStructuringElement(int shape, Size ksize, Point anchor = Point(-1, -1))

Devuelve un elemento estructurante del tamaño y la forma especificados, para su uso en operaciones morfológicas . Esta función construye y devuelve un elemento estructurante que puede ser pasado a erosión, dilatación o morfología. Pero también puede crear máscaras binarias arbitrarias y usarlas como elementos de estructuración.

  • void cv::dilate(InputArray src, OutputArray dst, InuputArray kernel, Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar &borderValue = morphologyDefaultBorderValue())

Inflar una imagen con elementos estructurantes específicos .

  • void cv::erode(InputArray src, OutputArray dst, InuputArray kernel, Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar &borderValue = morphologyDefaultBorderValue())

Corroe una imagen utilizando elementos estructurantes específicos .

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	string path = "resources/test.png";
	Mat img = imread(path);
	Mat imgGray, imgBlur, imgCanny, imgDil, imgErode;

	cvtColor(img, imgGray, COLOR_BGR2GRAY); //灰度化
	GaussianBlur(img, imgBlur, Size(3, 3), 3, 0); //高斯模糊
	Canny(imgBlur, imgCanny, 25, 75); //边缘检测

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	dilate(imgCanny, imgDil, kernel);
	erode(imgDil, imgErode, kernel);

	imshow("Image", img);
	imshow("ImageGray", imgGray);
	imshow("ImageBlur", imgBlur);
	imshow("ImageCanny", imgCanny);
	imshow("ImageDilation", imgDil);
	imshow("ImageErode", imgErode);
	waitKey(0);

	return 0;
}

cv2
cv3
cv4
cv5
cv6

Capítulo 3 Ajuste y recorte

  • void cv::resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation = INTER_LINEAR)

Ajusta el tamaño de la imagen . La función reduce o maximiza el tamaño de resizela imagen srcal tamaño especificado. Tenga en cuenta que el dsttipo o tamaño inicial no se considera. En cambio, el tamaño y el tipo se src、dsize、fx 和 fyderivan de .

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	string path = "resources/test.png";
	Mat img = imread(path);
	Mat imgResize, imgCrop;

	cout << img.size() << endl;
	resize(img, imgResize, Size(), 0.5, 0.5);

	Rect roi(200, 100, 300, 300);
	imgCrop = img(roi);

	imshow("Image", img);
	imshow("ImageResieze", imgResize);
	imshow("ImageCrop", imgCrop);
	waitKey(0);

	return 0;
}

cv7
cv8

Capítulo 4 Dibujar formas y texto

  • Mat(int rows, int cols, int type, const Scalar &s)

constructor sobrecargado

  • void cv::circle(InputOutputArray img, Point center, int radius, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)

La función cv::circle dibuja un círculo simple o lleno con el centro y el radio dados .

  • void cv::rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
  • void cv::rectangle(Mat &img, Rect rec, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)

Dibuja un rectángulo superior derecho simple, grueso o relleno . Función cv::rectangleDibuja un contorno rectangular o dos rectángulos rellenos con diagonales pt1 y pt2.

  • void cv::line (InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)

Dibuja un segmento de línea que conecta dos puntos . La función linedibuja un segmento de línea entre los puntos pt1 y pt2 en la imagen.

  • void cv::putText (InputOutputArray img, const String &text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=LINE_8, bool bottomLeftOrigin=false)

Dibuja una cadena de texto . Función cv::putTextRepresenta la cadena de texto especificada en una imagen. Los símbolos que no se pueden representar con la fuente especificada se reemplazarán con signos de interrogación.

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	//Blank Image
	Mat img(512, 512, CV_8UC3, Scalar(255, 255, 255));

	circle(img, Point(256, 256), 155, Scalar(0, 69, 255), FILLED);
	rectangle(img, Point(130, 226), Point(382, 286), Scalar(255, 255, 255), -1);
	line(img, Point(130, 296), Point(382, 296), Scalar(255, 255, 255), 2);

	putText(img, "SJN's Workshop", Point(137, 262), FONT_HERSHEY_DUPLEX, 0.95, Scalar(0, 69, 255), 2);

	imshow("Image", img);
	waitKey(0);

	return 0;
}

cv9

Transformación de la perspectiva del capítulo 5

  • Mat cv::getPerspectiveTransform (const Point2f src[], const Point2f dst[])

Devuelve la transformación de perspectiva 3x3 de los 4 pares de puntos correspondientes .

  • void cv::warpPerspective (InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar &borderValue=Scalar())

Aplica una transformación de perspectiva a la imagen .

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

float w = 250, h = 350;
Mat matrix, imgWarp;

int main()
{
	string path = "Resources/cards.jpg";
	Mat img = imread(path);

	Point2f src[4] = { {529, 142}, {771, 190}, {405, 395}, {674, 457} };
	Point2f dst[4] = { {0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h} };

	matrix = getPerspectiveTransform(src, dst);
	warpPerspective(img, imgWarp, matrix, Point(w, h));

	for (int i = 0; i < 4; i++) {
		circle(img, src[i], 10, Scalar(0, 0, 255), FILLED);
	}

	imshow("Image", img);
	imshow("ImageWarp", imgWarp);
	waitKey(0);

	return 0;
}

cv10
cv11
Nota: el escaneo de documentos utiliza esta técnica de transformación

Capítulo 6 Detección de color

  • void cv::inRange (InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)

Comprueba si un elemento de la matriz se encuentra entre los elementos de otras dos matrices.

  • void cv::namedWindow (const String &winname, int flags = WINDOW_AUTOSIZE)

Crea una ventana . La función namedWindowcrea una ventana que se puede utilizar como marcador de posición para imágenes y barras de seguimiento. Las ventanas creadas se referencian por sus nombres. Si ya existe una ventana con el mismo nombre, esta función no hace nada.

  • int cv::createTrackbar (const String &trackbarname, const String &winname, int *value, int count, TrackbarCallback onChange = 0, void *userdata = 0)

Cree uno trackbary adjúntelo a la ventana especificada . La función createTrackbarcrea un control (control deslizante o control de rango) con el nombre y el rango especificados trackbar, asigna un valor variable como trackbarla posición sincronizada y especifica una función de devolución de llamada onChangeque se llamará cuando cambie la posición de la barra de seguimiento. La barra de seguimiento creada se muestra en la ventana especificada winname.

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat imgHSV, mask;
int hmin = 0, smin = 110, vmin = 153;
int hmax = 19, smax = 240, vmax = 255;

int main()
{
	string path = "resources/lambo.png";
	Mat img = imread(path);
	cvtColor(img, imgHSV, COLOR_BGR2HSV);

	namedWindow("Trackbars", (640, 200));
	createTrackbar("Hue Min", "Trackbars", &hmin, 179);
	createTrackbar("Hue Max", "Trackbars", &hmax, 179);
	createTrackbar("Sat Min", "Trackbars", &smin, 255);
	createTrackbar("Sat Max", "Trackbars", &smax, 255);
	createTrackbar("Val Min", "Trackbars", &vmin, 255);
	createTrackbar("Val Max", "Trackbars", &vmax, 2555);

	while (true) {

		Scalar lower(hmin, smin, vmin);
		Scalar upper(hmax, smax, vmax);
		inRange(imgHSV, lower, upper, mask);

		imshow("Image", img);
		imshow("Image HSV", imgHSV);
		imshow("Image Mask", mask);
		waitKey(1);

	}

	return 0;
}

cv12
v13
cv14
cv15

Capítulo 7 Detección de forma/contorno

  • void cv::findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point())

Encuentra contornos en una imagen binaria . A partir de OpenCV3.2, esta función no modificará la imagen de origen.

parámetro significado
imagen imagen de entrada binaria
contornos Contornos detectados, cada uno almacenado como un vector de puntos (por ejemplo std::vector<std::vector<cv::Point> >)
jerarquía vector de salida opcional (p. ej. std::vector<cv::Vec4i>) que contiene información sobre la topología de la imagen
modo Modo de búsqueda de contorno
método aproximación de contorno
compensar desplazamiento opcional para mover cada punto del contorno
  • double cv::contourArea(InputArray contour, bool oriented=false)

Calcular área de contorno

  • double cv::arcLength(InputArray curve, bool closed)

Calcular la longitud de la curva o el perímetro del contorno cerrado

  • void cv::approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

La función cv::approxPolyDPaproxima una curva o polígono con otra curva/polígono con menos vértices de modo que la distancia entre ellos sea menor o igual a la precisión especificada .

  • Rect cv::boundingRect(InputArray array)

Calcula y devuelve el rectángulo límite superior mínimo de píxeles distintos de cero para el conjunto de puntos especificado o la imagen en escala de grises .

  • void cv::drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar &color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point())

Dibujar contornos de contorno o rellenar contornos . Si espesor ≥ 0, la función dibuja un contorno de contorno en la imagen, y si espesor < 0, rellena el área delimitada por el contorno.

  • Point_< _Tp > tl() const

esquina superior izquierda

  • Point_< _Tp > br() const

esquina inferior derecha

//rect
template<typename _Tp> class cv::Rect_< _Tp >
typedef Rect_<int> cv::Rect2i
typedef Rect2i cv::Rect
//point
template<typename _Tp> class cv::Point_< _Tp >
typedef Point_<int> cv::Point2i
typedef Point2i cv::Point

cv::Rect_< _Tp >atributo de clase significado
altura altura del rectángulo
ancho ancho del rectángulo
X la coordenada x de la esquina superior izquierda
y la coordenada y de la esquina superior izquierda
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void getContours(Mat imgDil, Mat img) {

	vector<vector<Point>> contours; //轮廓数据
	vector<Vec4i> hierarchy;

	findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //通过预处理的二值图像找到所有轮廓contours
	//drawContours(img, contours, -1, Scalar(255, 0, 255), 2); //绘制所有轮廓

	for (int i = 0; i < contours.size(); i++) 
	{
		double area = contourArea(contours[i]); //计算每个轮廓区域
		cout << area << endl;

		vector<vector<Point>> conPoly(contours.size()); 
		vector<Rect> boundRect(contours.size());
		string objectType;

		if (area > 1000) //过滤噪声
		{
			//找轮廓的近似多边形或曲线
			double peri = arcLength(contours[i], true);
			approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);
			
			cout << conPoly[i].size() << endl;
			boundRect[i] = boundingRect(conPoly[i]); //找每个近似曲线的最小上边界矩形
			
			int objCor = (int)conPoly[i].size();

			if (objCor == 3) { objectType = "Tri"; }
			if (objCor == 4) { 
				
				float aspRatio = (float)boundRect[i].width / boundRect[i].height; //宽高比
				cout << aspRatio << endl;
				if (aspRatio > 0.95 && aspRatio < 1.05) {
					objectType = "Square";
				}
				else {
					objectType = "Rect";
				}
			}
			if (objCor > 4) { objectType = "CirCle"; }

			drawContours(img, conPoly, i, Scalar(255, 0, 255), 2); //绘制滤除噪声后的所有轮廓
			rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5); //绘制边界框
			putText(img, objectType, { boundRect[i].x, boundRect[i].y - 5 }, FONT_HERSHEY_PLAIN, 1, Scalar(0, 69, 255), 1);
		}
	} 
}

int main()
{
	string path = "resources/shapes.png";
	Mat img = imread(path);
	Mat imgGray, imgBlur, imgCanny, imgDil;

	// Preprocessing
	cvtColor(img, imgGray, COLOR_BGR2GRAY);
	GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0);
	Canny(imgBlur, imgCanny, 25, 75);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	dilate(imgCanny, imgDil, kernel);

	getContours(imgDil, img);

	imshow("Image", img);
	/*imshow("Image Gray", imgGray);
	imshow("Image Blur", imgBlur);
	imshow("Image Canny", imgCanny);
	imshow("Image Dil", imgDil);*/

	waitKey(0);

	return 0;
}

cv16

Capítulo 8 Detección de rostros

Módulos involucradosobjdetect:Object Detection

  • class cv::CascadeClassifier

Clase de clasificador en cascada para la detección de objetos .

  • bool load (const String &filename)

Carga un clasificador desde un archivo.

  • bool empty() const

Compruebe si el clasificador está cargado.

  • void detectMultiScale(InputArray image, std::vector<Rect> &objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())

Detecta objetos de diferentes tamaños en una imagen de entrada. Los objetos detectados se devuelven como una lista de rectángulos.

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	string path = "Resources/test.png";
	Mat img = imread(path);

	CascadeClassifier faceCascade;
	faceCascade.load("Resources/haarcascade_frontalface_default.xml");

	if (faceCascade.empty()) { cout << "XML file not loaded" << endl; }

	vector<Rect> faces;
	faceCascade.detectMultiScale(img, faces, 1.1, 10);

	for (int i = 0; i < faces.size(); i++) 
	{
		rectangle(img, faces[i].tl(), faces[i].br(), Scalar(255, 0, 255), 3);
	}

	imshow("Image", img);
	waitKey(0);

	return 0;
}

cv17

Proyecto1 Pintor Virtual

Selector de color: primero averigüe el umbral HSV del color a detectar

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
	VideoCapture cap(1);
	Mat img;
	Mat imgHSV, mask, imgColor;
	int hmin = 0, smin = 0, vmin = 0;
	int hmax = 179, smax = 255, vmax = 255;

	namedWindow("Trackbars", (640, 200)); // Create Window
	createTrackbar("Hue Min", "Trackbars", &hmin, 179);
	createTrackbar("Hue Max", "Trackbars", &hmax, 179);
	createTrackbar("Sat Min", "Trackbars", &smin, 255);
	createTrackbar("Sat Max", "Trackbars", &smax, 255);
	createTrackbar("Val Min", "Trackbars", &vmin, 255);
	createTrackbar("Val Max", "Trackbars", &vmax, 255);

	while (true) {

		cap.read(img);
		cvtColor(img, imgHSV, COLOR_BGR2HSV);

		Scalar lower(hmin, smin, vmin);
		Scalar upper(hmax, smax, vmax);

		inRange(imgHSV, lower, upper, mask);
		// hmin, smin, vmin, hmax, smax, vmax;
		cout << hmin << ", " << smin << ", " << vmin << ", " << hmax << ", " << smax << ", " << vmax << endl;
		imshow("Image", img);
		imshow("Mask", mask);
		waitKey(1);
	}
}

Utilice el punto medio del límite superior del rectángulo de color detectado para iniciar la pintura virtual

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat img;
vector<vector<int>> newPoints;

vector<vector<int>> myColors{ {124, 48, 117, 143, 170, 255}, //purple
								{68, 72, 156, 102, 126, 255} }; //green

vector<Scalar> myColorValues{ {255, 0, 255}, //purple
								{0, 255, 0} }; //green

Point getContours(Mat imgDil) {

	vector<vector<Point>> contours; //轮廓数据
	vector<Vec4i> hierarchy;

	findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //通过预处理的二值图像找到所有轮廓contours
	//drawContours(img, contours, -1, Scalar(255, 0, 255), 2); //绘制所有轮廓(不滤除噪声)
	vector<vector<Point>> conPoly(contours.size());
	vector<Rect> boundRect(contours.size());
	Point myPoint(0, 0);

	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]); //计算每个轮廓区域
		cout << area << endl;

		if (area > 1000) //过滤噪声
		{
			//找轮廓的近似多边形或曲线
			double peri = arcLength(contours[i], true);
			approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);

			cout << conPoly[i].size() << endl;
			boundRect[i] = boundingRect(conPoly[i]); //找每个近似曲线的最小上边界矩形
			myPoint.x = boundRect[i].x + boundRect[i].width / 2;
			myPoint.y = boundRect[i].y;

			//drawContours(img, conPoly, i, Scalar(255, 0, 255), 2); //绘制滤除噪声后的所有轮廓
			//rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5); //绘制边界框
		}
	}
	return myPoint; //返回矩形框上边界中点坐标
}

vector<vector<int>> findColor(Mat img)
{
	Mat imgHSV, mask;
	cvtColor(img, imgHSV, COLOR_BGR2HSV);

	for (int i = 0; i < myColors.size(); i++) 
	{
		Scalar lower(myColors[i][0], myColors[i][1], myColors[i][2]);
		Scalar upper(myColors[i][3], myColors[i][4], myColors[i][5]);
		inRange(imgHSV, lower, upper, mask);
		//imshow(to_string(i), mask);
		Point myPoint = getContours(mask); //根据mask得到检测到当前颜色矩形框的上边界中点坐标

		if (myPoint.x != 0 && myPoint.y != 0) 
		{
			newPoints.push_back({ myPoint.x, myPoint.y, i }); //得到当前帧检测颜色的目标点
		}
	}
	return newPoints;
}

void drawOnCanvas(vector<vector<int>> newPoints, vector<Scalar> myColorValues)
{
	for (int i = 0; i < newPoints.size(); i++) 
	{
		circle(img, Point(newPoints[i][0], newPoints[i][1]), 10, myColorValues[newPoints[i][2]], FILLED);
	}
}

int main()
{
	VideoCapture cap(0);

	while (true) 
	{
		cap.read(img);
		newPoints = findColor(img);
		drawOnCanvas(newPoints, myColorValues);

		imshow("Image", img);
		waitKey(1);
	}

	return 0;
}

Escaneo de documentos de Project2

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat imgOriginal, imgGray, imgBlur,imgCanny, imgThre, imgDil, imgErode, imgWarp, imgCrop;
vector<Point> initialPoints, docPoints;

float w = 420, h = 596;

Mat preProcessing(Mat img)
{
	cvtColor(img, imgGray, COLOR_BGR2GRAY); 
	GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0); 
	Canny(imgBlur, imgCanny, 25, 75); 

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	dilate(imgCanny, imgDil, kernel);
	//erode(imgDil, imgErode, kernel);
	return imgDil;
}

vector<Point> getContours(Mat imgDil) {

	vector<vector<Point>> contours; //轮廓数据
	vector<Vec4i> hierarchy;

	findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //通过预处理的二值图像找到所有轮廓contours
	//drawContours(img, contours, -1, Scalar(255, 0, 255), 2); //绘制所有轮廓(不滤除噪声)
	vector<vector<Point>> conPoly(contours.size());
	vector<Point> biggest;
	int maxArea = 0;

	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]); //计算每个轮廓区域
		cout << area << endl;

		if (area > 1000) //过滤噪声
		{
			//找轮廓的近似多边形或曲线
			double peri = arcLength(contours[i], true);
			approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);

			if (area > maxArea && conPoly[i].size() == 4) {

				//drawContours(imgOriginal, conPoly, i, Scalar(255, 0, 255), 5); //绘制滤除噪声后的所有轮廓
				biggest = { conPoly[i][0], conPoly[i][1], conPoly[i][2], conPoly[i][3] };
				maxArea = area;

			}
		}
	}
	return biggest; //返回最大轮廓四个点的坐标
}

void drawPoints(vector<Point> points, Scalar color)
{
	for (int i = 0; i < points.size(); i++) 
	{
		circle(imgOriginal, points[i], 10, color, FILLED);
		putText(imgOriginal, to_string(i), points[i], FONT_HERSHEY_PLAIN, 4, color, 4);
	}
}

vector<Point> reorder(vector<Point> points)
{
	vector<Point> newPoints;
	vector<int> sumPoints, subPoints;

	for (int i = 0; i < 4; i++) 
	{
		sumPoints.push_back(points[i].x + points[i].y);
		subPoints.push_back(points[i].x - points[i].y);
	}

	newPoints.push_back(points[min_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]); //0
	newPoints.push_back(points[max_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]); //1
	newPoints.push_back(points[min_element(subPoints.begin(), subPoints.end()) - subPoints.begin()]); //2
	newPoints.push_back(points[max_element(sumPoints.begin(), sumPoints.end()) - sumPoints.begin()]); //3

	return newPoints;
}

Mat getWarp(Mat img, vector<Point> points, float w, float h)
{
	Point2f src[4] = { points[0], points[1], points[2], points[3] };
	Point2f dst[4] = { {0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h} };

	Mat matrix = getPerspectiveTransform(src, dst);
	warpPerspective(img, imgWarp, matrix, Point(w, h));
	return imgWarp;
}

int main()
{
	string path = "Resources/paper.jpg";
	imgOriginal = imread(path);
	//resize(imgOriginal, imgOriginal, Size(), 0.5, 0.5);

	//Preprocessing
	imgThre = preProcessing(imgOriginal);
	//Get Contours - Biggest
	initialPoints = getContours(imgThre);
	//drawPoints(initialPoints, Scalar(0, 0, 255));
	docPoints = reorder(initialPoints);
	//drawPoints(docPoints, Scalar(0, 255, 0));

	//Warp
	imgWarp = getWarp(imgOriginal, docPoints, w, h);

	//Crop
	int cropValue = 5;
	Rect roi(cropValue, cropValue, w - (2 * cropValue), h - (2 * cropValue));
	imgCrop = imgWarp(roi);

	imshow("Image", imgOriginal);
	imshow("Image Dilation", imgThre);
	imshow("Image Warp", imgWarp);
	imshow("Image Crop", imgCrop);
	waitKey(0);

	return 0;
}

cv18
cv19

Detección de matrículas de Project3

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	VideoCapture cap(0);
	Mat img;

	CascadeClassifier plateCascade;
	plateCascade.load("Resources/haarcascade_russian_plate_number.xml");

	if (plateCascade.empty()) { cout << "XML file not loaded" << endl; }

	vector<Rect> plates;

	while (true) {

		cap.read(img);

		plateCascade.detectMultiScale(img, plates, 1.1, 10);

		for (int i = 0; i < plates.size(); i++)
		{
			Mat imgCrop = img(plates[i]);
			imshow(to_string(i), imgCrop);
			imwrite("D:\\VS2019Projects\\chapter2\\chapter2\\resources\\Plates\\1.png", imgCrop);
			rectangle(img, plates[i].tl(), plates[i].br(), Scalar(255, 0, 255), 3);
		}

		imshow("Image", img);
		waitKey(1);
	}
	return 0;
}

Digresión

Muchas personas que son nuevas en la industria informática o que se graduaron de carreras relacionadas con la informática han encontrado obstáculos en todas partes debido a la falta de experiencia práctica. Veamos dos conjuntos de datos:

  • Se espera que los graduados universitarios nacionales de 2023 alcancen los 11,58 millones, y la situación laboral es grave;

  • Según los datos publicados por la Semana Nacional de Publicidad de Seguridad en Redes, para el año 2027, la escasez de personal de seguridad en redes en mi país llegará a 3,27 millones.

Por un lado, la situación laboral de los recién graduados es grave cada año y, por otro lado, existe una brecha de un millón de talentos en ciberseguridad.

El 9 de junio, se publicó oficialmente la edición de 2023 del Libro azul de empleo de MyCOS Research (que incluye el Informe de empleo de 2023 para estudiantes universitarios en China y el Informe de empleo para estudiantes de formación profesional superior en China en 2023).

Las 10 carreras principales con salario mensual más alto para graduados universitarios de 2022

El ingreso mensual de los estudiantes de pregrado en ciencias de la computación y de los estudiantes de automatización vocacional superior es relativamente alto. El ingreso mensual de la clase 2022 de licenciatura en informática y carreras de automatización vocacional superior es de 6.863 yuanes y 5.339 yuanes, respectivamente. Entre ellos, el salario inicial de los estudiantes de licenciatura en informática es básicamente el mismo que el de la clase 2021, y el ingreso mensual de los estudiantes de automatización vocacional superior ha aumentado significativamente.

Específicamente, dependiendo de la carrera, la carrera con un ingreso mensual más alto para estudiantes universitarios en 2022 es seguridad de la información (7579 yuanes). En comparación con la clase de 2018, las carreras universitarias relacionadas con la inteligencia artificial, como la ciencia y la tecnología electrónica, la automatización, tuvieron un buen desempeño y sus salarios iniciales aumentaron un 19 % en comparación con hace cinco años. Si bien la ciencia de datos y la tecnología de big data son especializaciones recientemente agregadas en los últimos años, han tenido un buen desempeño y se han clasificado entre las tres principales especializaciones con ingresos mensuales más altos medio año después de la graduación para la clase de estudiantes universitarios de 2022. La única especialidad en humanidades y ciencias sociales que ingresó a la lista de los 10 mejores estudiantes mejor pagados hace cinco años, French ha salido del top 10.

“No hay seguridad nacional sin ciberseguridad”. En la actualidad, la seguridad de la red se ha elevado a la altura de la estrategia nacional y se ha convertido en uno de los factores más importantes que afectan la seguridad nacional y la estabilidad social.

Características de la industria de seguridad de redes

1. El salario de empleo es muy alto y aumenta rápidamente. En 2021, Liepin.com lanzó el salario de empleo más alto en la industria de seguridad de redes, ¡que es de 337,700 yuanes per cápita!

2. Hay una gran brecha de talento y muchas oportunidades de empleo

El 18 de septiembre de 2019, el sitio web oficial del "Gobierno Popular Central de la República Popular China" publicó: mi país necesita 1,4 millones de talentos en seguridad cibernética, pero las escuelas de todo el país capacitan a menos de 1,5 millones de personas cada año. El "Informe de seguridad cibernética para la primera mitad de 2021" de Liepin.com predice que la demanda de talentos en seguridad cibernética será de 3 millones en 2027, y solo hay 100,000 empleados actualmente involucrados en la industria de la seguridad cibernética.

La industria tiene mucho espacio para el desarrollo y muchos puestos de trabajo

Desde el establecimiento de la industria de seguridad de redes, se han agregado docenas de nuevos puestos en la industria de seguridad de redes: expertos en seguridad de redes, analistas de seguridad de redes, consultores de seguridad, ingenieros de seguridad de redes, arquitectos de seguridad, ingenieros de operaciones y mantenimiento de seguridad, ingenieros de penetración, administradores de seguridad de la información, ingenieros de seguridad de datos, ingenieros de operaciones de seguridad de redes, ingenieros de respuesta a emergencias de seguridad de redes, evaluadores de datos, gerentes de productos de seguridad de redes, ingenieros de servicios de seguridad de redes, capacitadores de seguridad de redes, auditores de seguridad de redes, ingenieros de análisis de inteligencia de amenazas, profesionales de recuperación ante desastres, profesionales de ataque y defensa de combate...

Gran potencial de carrera

La especialización en seguridad de redes tiene características técnicas sólidas, especialmente el dominio de la arquitectura de red central y la tecnología de seguridad en el trabajo, lo que tiene una ventaja competitiva insustituible en el desarrollo profesional.

Con la mejora continua de la capacidad personal, el valor profesional del trabajo también aumentará con el enriquecimiento de la propia experiencia y la madurez de la operación del proyecto, y el espacio de apreciación es alcista en todo momento, que es la razón principal por la que es popular entre todos.

Hasta cierto punto, en el campo de la seguridad de la red, al igual que en la profesión de médico, cuanto mayor sea, más popular se vuelve. Debido a que la tecnología se vuelve más madura, el trabajo se valorará naturalmente, y la promoción y el aumento salarial son una cuestión de rutina.

Cómo aprender piratería y seguridad cibernética

Hoy, siempre que le dé su visto bueno a mi artículo, compartiré con usted mi colección privada de materiales de aprendizaje de seguridad en línea de forma gratuita, así que veamos qué hay allí.

1. Hoja de ruta de aprendizaje

También hay muchas cosas que aprender en ataque y defensa. He escrito todas las cosas específicas para aprender en la hoja de ruta anterior. Si puede aprenderlas, no tendrá problemas para conseguir un trabajo o tomar trabajos privados.

2. Videotutorial

Aunque hay muchos recursos de aprendizaje en Internet, básicamente están incompletos. Este es un video tutorial sobre seguridad cibernética grabado por mí. Tengo una explicación en video de apoyo para cada punto de conocimiento en la hoja de ruta anterior.

El contenido abarca el estudio de la ley de seguridad de redes, operación de seguridad de redes y otras evaluaciones de garantías, conceptos básicos de pruebas de penetración, explicación detallada de vulnerabilidades, conocimientos básicos de informática, etc., que son todos los contenidos de aprendizaje que se deben conocer al iniciarse en la seguridad de redes.

(Todo está empaquetado en una sola pieza y no se puede desplegar uno por uno. Hay más de 300 episodios en total)

Debido al espacio limitado, solo se muestra una parte de la información, debe hacer clic en el enlace a continuación para obtenerla

Juerga de CSDN: "Paquete de recursos de aprendizaje avanzado y introducción a la seguridad de redes y piratas informáticos" uso compartido gratuito

3. Documentos técnicos y libros electrónicos

Los documentos técnicos también son compilados por mí mismo, incluyendo mi experiencia y puntos técnicos de participación en operaciones de seguridad de redes a gran escala, minería de vulnerabilidades CTF y SRC. También hay más de 200 libros electrónicos. Debido a la sensibilidad del contenido, no los mostraré uno por uno.

Debido al espacio limitado, solo se muestra una parte de la información, debe hacer clic en el enlace a continuación para obtenerla

Juerga de CSDN: "Paquete de recursos de aprendizaje avanzado y introducción a la seguridad de redes y piratas informáticos" uso compartido gratuito

4. Caja de herramientas, preguntas de la entrevista y código fuente

“Si quieres hacer un buen trabajo, primero debes afilar tus herramientas.” He resumido docenas de las herramientas de hackeo más populares para todos. El alcance de la cobertura se centra principalmente en la recopilación de información, las herramientas de piratería de Android, las herramientas de automatización, el phishing, etc. Los estudiantes interesados ​​no se lo deben perder.

También está el código fuente del caso y el conjunto de herramientas correspondiente mencionado en mi video, que se puede quitar si es necesario.

Debido al espacio limitado, solo se muestra una parte de la información, debe hacer clic en el enlace a continuación para obtenerla

Juerga de CSDN: "Paquete de recursos de aprendizaje avanzado y introducción a la seguridad de redes y piratas informáticos" uso compartido gratuito

Finalmente, hay preguntas de la entrevista sobre seguridad en Internet que he resuelto en los últimos años. Si está buscando un trabajo en seguridad en Internet, definitivamente lo ayudarán mucho.

Estas preguntas se encuentran a menudo en entrevistas con Sangfor, Qi Anxin, Tencent u otras empresas importantes. Si tiene buenas preguntas o buenas ideas, compártalas.

Análisis de referencia: sitio web oficial de Sangfor, sitio web oficial de Qi Anxin, Freebuf, csdn, etc.

Características del contenido: organización clara, incluida la representación gráfica, que es más fácil de entender.

Resumen de contenido: Incluye intranet, sistema operativo, protocolo, pruebas de penetración, servicio de seguridad, vulnerabilidad, inyección, XSS, CSRF, SSRF, carga de archivos, descarga de archivos, inclusión de archivos, XXE, vulnerabilidad lógica, herramienta, SQLmap, NMAP, BP, MSF...

Debido al espacio limitado, solo se muestra una parte de la información, debe hacer clic en el enlace a continuación para obtenerla

Juerga de CSDN: "Paquete de recursos de aprendizaje avanzado y introducción a la seguridad de redes y piratas informáticos" uso compartido gratuito

Supongo que te gusta

Origin blog.csdn.net/Python_0011/article/details/131871546
Recomendado
Clasificación