C++ 如何获取我的C++;检测Ñ;
我正在做一个OCR项目,我正处于培训阶段,因此我的程序的目标是将字符检测为图像中的对象,并允许对其进行分类。 问题是,我不能用ñ得到它,因为它是由两个对象(N和棍子)组成的 你知道有没有办法把它归类为一个物体 节目如下:C++ 如何获取我的C++;检测Ñ;,c++,opencv,ocr,C++,Opencv,Ocr,我正在做一个OCR项目,我正处于培训阶段,因此我的程序的目标是将字符检测为图像中的对象,并允许对其进行分类。 问题是,我不能用ñ得到它,因为它是由两个对象(N和棍子)组成的 你知道有没有办法把它归类为一个物体 节目如下: #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<o
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/ml/ml.hpp>
#include<iostream>
#include<vector>
// global variables
const int MIN_CONTOUR_AREA = 30;
const int RESIZED_IMAGE_WIDTH = 20;
const int RESIZED_IMAGE_HEIGHT = 30;
//////////////////////////////////////
int main() {
cv::Mat imgTrainingNumbers; // input image
cv::Mat imgGrayscale; //
cv::Mat imgBlurred; // declare various images
cv::Mat imgThresh; //
cv::Mat imgThreshCopy; //
std::vector<std::vector<cv::Point> > ptContours; // declare contours vector
std::vector<cv::Vec4i> v4iHierarchy; // declare contours hierarchy
cv::Mat matClassificationInts; // these are our training classifications, note we will have to perform some conversions before writing to file later
// these are our training images, due to the data types that the KNN object KNearest requires, we have to declare a single Mat,
// then append to it as though it's a vector, also we will have to perform some conversions before writing to file later
cv::Mat matTrainingImagesAsFlattenedFloats;
// possible chars we are interested in are digits 0 through 9 and capital letters A through Z, put these in vector intValidChars
std::vector<int> intValidChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'};
imgTrainingNumbers = cv::imread("caracteres_prueba.png"); // read in training numbers image
if (imgTrainingNumbers.empty()) { // if unable to open image
std::cout << "error: image not read from file\n\n"; // show error message on command line
return(0); // and exit program
}
cv::cvtColor(imgTrainingNumbers, imgGrayscale, CV_BGR2GRAY); // convert to grayscale
cv::GaussianBlur(imgGrayscale, // input image
imgBlurred, // output image
cv::Size(5, 5), // smoothing window width and height in pixels
0); // sigma value, determines how much the image will be blurred, zero makes function choose the sigma value
// filter image from grayscale to black and white
cv::adaptiveThreshold(imgBlurred, // input image
imgThresh, // output image
255, // make pixels that pass the threshold full white
cv::ADAPTIVE_THRESH_GAUSSIAN_C, // use gaussian rather than mean, seems to give better results
cv::THRESH_BINARY_INV, // invert so foreground will be white, background will be black
11, // size of a pixel neighborhood used to calculate threshold value
2); // constant subtracted from the mean or weighted mean
cv::imshow("imgThresh", imgThresh); // show threshold image for reference
imgThreshCopy = imgThresh.clone(); // make a copy of the thresh image, this in necessary b/c findContours modifies the image
cv::findContours(imgThreshCopy, // input image, make sure to use a copy since the function will modify this image in the course of finding contours
ptContours, // output contours
v4iHierarchy, // output hierarchy
cv::RETR_EXTERNAL, // retrieve the outermost contours only
cv::CHAIN_APPROX_SIMPLE); // compress horizontal, vertical, and diagonal segments and leave only their end points
for (int i = 0; i < ptContours.size(); i++) { // for each contour
if (cv::contourArea(ptContours[i]) > MIN_CONTOUR_AREA) { // if contour is big enough to consider
cv::Rect boundingRect = cv::boundingRect(ptContours[i]); // get the bounding rect
cv::rectangle(imgTrainingNumbers, boundingRect, cv::Scalar(0, 0, 255), 2); // draw red rectangle around each contour as we ask user for input
cv::Mat matROI = imgThresh(boundingRect); // get ROI image of bounding rect
cv::Mat matROIResized;
cv::resize(matROI, matROIResized, cv::Size(RESIZED_IMAGE_WIDTH, RESIZED_IMAGE_HEIGHT)); // resize image, this will be more consistent for recognition and storage
cv::imshow("matROI", matROI); // show ROI image for reference
cv::imshow("matROIResized", matROIResized); // show resized ROI image for reference
cv::imshow("imgTrainingNumbers", imgTrainingNumbers); // show training numbers image, this will now have red rectangles drawn on it
int intChar = cv::waitKey(0); // get key press
if (intChar == 27) { // if esc key was pressed
return(0); // exit program
}
else if (std::find(intValidChars.begin(), intValidChars.end(), intChar) != intValidChars.end()) { // else if the char is in the list of chars we are looking for . . .
matClassificationInts.push_back(intChar); // append classification char to integer list of chars
cv::Mat matImageFloat; // now add the training image (some conversion is necessary first) . . .
matROIResized.convertTo(matImageFloat, CV_32FC1); // convert Mat to float
cv::Mat matImageFlattenedFloat = matImageFloat.reshape(1, 1); // flatten
matTrainingImagesAsFlattenedFloats.push_back(matImageFlattenedFloat); // add to Mat as though it was a vector, this is necessary due to the
// data types that KNearest.train accepts
} // end if
} // end if
} // end for
std::cout << "training complete\n\n";
// save classifications to file ///////////////////////////////////////////////////////
cv::FileStorage fsClassifications("classifications.xml", cv::FileStorage::WRITE); // open the classifications file
if (fsClassifications.isOpened() == false) { // if the file was not opened successfully
std::cout << "error, unable to open training classifications file, exiting program\n\n"; // show error message
return(0); // and exit program
}
fsClassifications << "classifications" << matClassificationInts; // write classifications into classifications section of classifications file
fsClassifications.release(); // close the classifications file
// save training images to file ///////////////////////////////////////////////////////
cv::FileStorage fsTrainingImages("images.xml", cv::FileStorage::WRITE); // open the training images file
if (fsTrainingImages.isOpened() == false) { // if the file was not opened successfully
std::cout << "error, unable to open training images file, exiting program\n\n"; // show error message
return(0); // and exit program
}
fsTrainingImages << "images" << matTrainingImagesAsFlattenedFloats; // write training images into images section of images file
fsTrainingImages.release(); // close the training images file
return(0);
#包括
#包括
#包括
#包括
#包括
#包括
//全局变量
const int MIN_等高线面积=30;
const int大小调整后的图像宽度=20;
const int RESIZED_IMAGE_HEIGHT=30;
//////////////////////////////////////
int main(){
cv::Mat imgTrainingNumbers;//输入图像
cv::Mat imgGrayscale;//
cv::Mat imgBlurred;//声明各种图像
cv::Mat imgThresh//
cv::Mat imgThreshCopy//
std::vector ptcourts;//声明轮廓向量
std::vector v4iHierarchy;//声明轮廓层次结构
cv::Mat MatClassificationts;//这些是我们的培训分类,请注意,在稍后写入文件之前,我们必须执行一些转换
//这些是我们的训练图像,由于KNN对象KNearest需要的数据类型,我们必须声明一个Mat,
//然后附加到它,就像它是一个向量一样,我们还必须在稍后写入文件之前执行一些转换
cv::Matt Mattraining Images展平浮点数;
//我们感兴趣的可能字符是数字0到9和大写字母A到Z,将它们放入向量intValidChars中
std::vector intValidChars={'0','1','2','3','4','5','6','7','8','9',',
‘A’、‘B’、‘C’、‘D’、‘E’、‘F’、‘G’、‘H’、‘I’、‘J’,
‘K’、‘L’、‘M’、‘N’、‘O’、‘P’、‘Q’、‘R’、‘S’、‘T’,
‘U’、‘V’、‘W’、‘X’、‘Y’、‘Z’};
imgTrainingNumbers=cv::imread(“caracteres_prueba.png”);//读取训练数字图像
if(imgTrainingNumbers.empty()){//if无法打开映像
STD::Couth-MixCouthUl区域){//如果轮廓足够大,可以考虑
cv::Rect boundingRect=cv::boundingRect(ptContours[i]);//获取边界矩形
cv::rectangle(imgTrainingNumbers,boundingRect,cv::Scalar(0,0,255),2);//当我们要求用户输入时,在每个轮廓周围绘制红色矩形
cv::Mat matROI=imgThresh(boundingRect);//获取boundingRect的ROI图像
cv::Mat拟阵化;
cv::resize(matROI,MATRORIZED,cv::Size(RESIZED_IMAGE_WIDTH,RESIZED_IMAGE_HEIGHT));//调整图像大小,这将使识别和存储更加一致
cv::imshow(“matROI”,matROI);//显示ROI图像以供参考
cv::imshow(“拟阵化”,拟阵化);//显示调整大小的ROI图像以供参考
cv::imshow(“imgTrainingNumbers”,imgTrainingNumbers);//显示训练编号图像,现在将在其上绘制红色矩形
int intChar=cv::waitKey(0);//获取按键
如果(intChar==27){//如果按了esc键
返回(0);//退出程序
}
else if(std::find(intValidChars.begin(),intValidChars.end(),intChar)!=intValidChars.end()){//else如果字符在我们要查找的字符列表中。
matClassificationts.push_back(intChar);//将分类字符附加到字符的整数列表中
cv::Mat matImageFloat;//现在添加训练图像(首先需要进行一些转换)。
MatroResized.convertTo(matImageFloat,CV_32FC1);//将Mat转换为float
cv::Mat MatimageFlattedFloat=matImageFloat.Reformate(1,1);//展平
MattrainingImagesAsFlattedFloats.push_back(MatImageFlattedFloat);//将其添加到Mat,就像它是一个向量一样,这是必要的,因为
//KNearest.train接受的数据类型
}//如果结束,则结束
}//如果结束,则结束
}//结束
std::cout首先,您在
int intChar = cv::waitKey(0);
一定是
char intChar = cv::waitKey(0);
试试看,如果有错误告诉我,你可以在附近(垂直方向)聚集轮廓。这也是“i”的问题。(用英语编写代码也可能有帮助)对不起,我忘记编辑代码了,但我已经编辑过了,谢谢!将它们训练为两个独立的字符有什么问题,但在检测时,您可以编写特殊情况,将两个字符的检测视为单个字符。int intChar=cv::waitKey(0)
完全可以。但是当您从屏幕上获取字符时,您必须声明作为char to可以获取数字和字符……。我以前使用过该代码,所以我告诉您发生了什么事cv::waitKey
如果您按下任何键,将返回大于127的值,从而溢出char
变量(范围从-128到127)因此,不建议将密钥代码存储在<代码> char 变量中。无论如何,您的答案与OP的问题无关,所以您应该考虑删除它。我知道,但是CV::WaTKEY将从您输入的键盘取值,因此如果它是int,则只取数字,但如果字符是字符和数字,那么它将取字符和数字。