energy changed

This commit is contained in:
sun
2019-07-09 13:55:40 +08:00
parent cc508cfec5
commit 6d06b4bf5c
9 changed files with 232 additions and 39 deletions

View File

@@ -41,8 +41,10 @@ private:
int fans_cnt;//图像中的扇叶个数
int armors_cnt;//图像中的装甲板个数
int centerRs_cnt;//图像中可能的风车中心字母R选区个数
int flow_strips_cnt;//图像中的流动条个数
int last_fans_cnt;//上一帧的扇叶个数
int last_armors_cnt;//上一帧的装甲板个数
int last_flow_strips_cnt;//
int gimble_cnt; //经过的帧数
double radius;//大风车半径
float target_polar_angle;//待击打装甲板的极坐标角度
@@ -67,6 +69,7 @@ private:
std::vector<EnergyPart> fans;//图像中所有扇叶
std::vector<EnergyPart> armors;//图像中所有装甲板
std::vector<EnergyPart> centerRs;//风车中心字母R的可能候选区
std::vector<EnergyPart> flow_strips;//图像中所有流动条(理论上只有一个)
cv::Point circle_center_point;//风车圆心坐标
cv::Point target_point;//目标装甲板中心坐标
@@ -85,15 +88,18 @@ private:
int findFan(const cv::Mat src, int &last_fans_cnt);//寻找图中所有扇叶
int findArmor(const cv::Mat src, int &last_armors_cnt);//寻找图中所有装甲板
int findCenterR(const cv::Mat src);//寻找图中可能的风车中心字母R
int findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt);//寻找图中所有流动条
bool isValidFanContour(const vector<cv::Point> fan_contour);//扇叶矩形尺寸要求
bool isValidArmorContour(const vector<cv::Point> armor_contour);//装甲板矩形尺寸要求
bool isValidCenterRContour(const vector<cv::Point> center_R_contour);//风车中心选区尺寸要求
bool isValidFlowStripContour(const vector<cv::Point> flow_strip_contour);//流动条矩形尺寸要求
void showFanContours(std::string windows_name, const cv::Mat src);//显示扇叶
void showArmorContours(std::string windows_name, const cv::Mat src);//显示装甲板
void showBothContours(std::string windows_name, const cv::Mat src);//显示扇叶和装甲板
void showCenterRContours(std::string windows_name, const cv::Mat src);//显示风车中心候选区R
void showFlowStripContours(std::string windows_name, const cv::Mat src);//显示流动条
void getFanPolarAngle();//获取扇叶极坐标角度
void getArmorPolarAngle();//获取装甲板极坐标角度
@@ -103,6 +109,7 @@ private:
void findTargetByPolar();//通过极坐标角度匹配获取目标装甲板的极坐标角度和装甲板中心坐标
void findTargetByIntersection();//通过面积重合度匹配获取目标装甲板的极坐标角度和装甲板中心坐标
bool findTargetInFlowStrip();//在已发现的流动条区域中寻找待击打装甲板
void rotate();//获取预测点位
void stretch(cv::Point point_1, cv::Point2f &point_2);//将像素差转换为实际距离差

View File

@@ -45,6 +45,7 @@ struct EnergyPartParam {
long FAN_CONTOUR_WIDTH_MAX;//扇叶宽边长度最大值
float FAN_CONTOUR_HW_RATIO_MAX;//扇叶长宽比最大值
float FAN_CONTOUR_HW_RATIO_MIN;//扇叶长宽比最小值
float FAN_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值
long ARMOR_CONTOUR_AREA_MAX;//装甲板面积最大值
long ARMOR_CONTOUR_AREA_MIN;//装甲板面积最小值
@@ -54,6 +55,7 @@ struct EnergyPartParam {
long ARMOR_CONTOUR_WIDTH_MAX;//装甲板宽边长度最大值
float ARMOR_CONTOUR_HW_RATIO_MAX;//装甲板长宽比最大值
float ARMOR_CONTOUR_HW_RATIO_MIN;//装甲板长宽比最小值
float ARMOR_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值
long CENTER_R_CONTOUR_AREA_MAX;//风车中心R面积最大值
long CENTER_R_CONTOUR_AREA_MIN;//风车中心R面积最小值
@@ -63,13 +65,24 @@ struct EnergyPartParam {
long CENTER_R_CONTOUR_WIDTH_MAX;//风车中心R宽边长度最大值
float CENTER_R_CONTOUR_HW_RATIO_MAX;//风车中心R长宽比最大值
float CENTER_R_CONTOUR_HW_RATIO_MIN;//风车中心R长宽比最小值
float CENTER_R_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值
long FLOW_LIGHT_CONTOUR_HW_RATIO_MIN;//流动条长宽比最小值_
long FLOW_STRIP_CONTOUR_AREA_MAX;//流动条(待击打)面积最大值
long FLOW_STRIP_CONTOUR_AREA_MIN;//流动条(待击打)面积最小值
long FLOW_STRIP_CONTOUR_LENGTH_MIN;//流动条(待击打)长边长度最小值
long FLOW_STRIP_CONTOUR_WIDTH_MIN;//流动条(待击打)长边长度最大值
long FLOW_STRIP_CONTOUR_LENGTH_MAX;//流动条(待击打)宽边长度最小值
long FLOW_STRIP_CONTOUR_WIDTH_MAX;//流动条(待击打)宽边长度最大值
float FLOW_STRIP_CONTOUR_HW_RATIO_MAX;//流动条(待击打)长宽比最大值
float FLOW_STRIP_CONTOUR_HW_RATIO_MIN;//流动条(待击打)长宽比最小值
float FLOW_STRIP_CONTOUR_AREA_RATIO_MAX;//装甲板轮廓占旋转矩形面积比最小值
float FLOW_STRIP_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值
float TWIN_ANGEL_MAX;//扇叶和装甲板匹配时极坐标角度差的最大值
long INTERSETION_CONTOUR_AREA_MIN;//扇叶与装甲板匹配时的最小重合面积
long TARGET_CHANGE_DISTANCE_MAX;//目标未更改时,目标装甲板中心与原目标装甲板中心的距离变化最大值
long TWIN_POINT_MAX;//两个点相同时距离最大值
};

View File

@@ -27,7 +27,8 @@ void Energy::StructingElementClose(cv::Mat &src,int length, int width){
void Energy::StructingElementErodeDilate(cv::Mat &src) {
cv::Mat src_out, src_out_out;
Mat element_dilate_1 = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat element_erode_1 = getStructuringElement(MORPH_RECT, Size(3, 4));
// Mat element_erode_1 = getStructuringElement(MORPH_RECT, Size(3, 4));
Mat element_erode_1 = getStructuringElement(MORPH_RECT, Size(2, 1));
Mat element_dilate_2 = getStructuringElement(MORPH_RECT, Size(8, 6));
Mat element_erode_2 = getStructuringElement(MORPH_RECT, Size(4 , 4));
Mat element_dilate_3 = getStructuringElement(MORPH_RECT, Size(3, 3));

View File

@@ -20,6 +20,7 @@ void Energy::initEnergy() {
fans_cnt = 0;
armors_cnt = 0;
centerRs_cnt = 0;
flow_strips_cnt = 0;
gimble_cnt = 0;
circle_center_point = Point(0, 0);
target_point = Point(0, 0);
@@ -33,6 +34,7 @@ void Energy::initEnergy() {
attack_distance = ATTACK_DISTANCE;
last_fans_cnt = 0;
last_armors_cnt = 0;
last_flow_strips_cnt = 0;
send_cnt = 0;
yaw_rotation = 0;
pitch_rotation = 0;
@@ -51,6 +53,7 @@ void Energy::initEnergy() {
fans.clear();
armors.clear();
centerRs.clear();
flow_strips.clear();
fan_polar_angle.clear();
armor_polar_angle.clear();
@@ -72,7 +75,7 @@ void Energy::initEnergyPartParam() {
energy_part_param_.FAN_GRAY_THRESH = 75;
energy_part_param_.ARMOR_GRAY_THRESH = 80;
energy_part_param_.FAN_CONTOUR_AREA_MAX = 17000;
/*energy_part_param_.FAN_CONTOUR_AREA_MAX = 17000;
energy_part_param_.FAN_CONTOUR_AREA_MIN = 0;
energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 70;
energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 100;
@@ -88,7 +91,27 @@ void Energy::initEnergyPartParam() {
energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX = 30;
energy_part_param_.ARMOR_CONTOUR_WIDTH_MAX = 20;
energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX = 3;
energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN = 1;
energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN = 1;*/
energy_part_param_.FAN_CONTOUR_AREA_MAX = 17000;
energy_part_param_.FAN_CONTOUR_AREA_MIN = 0;
energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 90;
energy_part_param_.FAN_CONTOUR_WIDTH_MIN = 35;
energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 140;
energy_part_param_.FAN_CONTOUR_WIDTH_MAX = 60;
energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX = 4;
energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN = 1;
energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN = 0.6;
energy_part_param_.ARMOR_CONTOUR_AREA_MAX = 100000;
energy_part_param_.ARMOR_CONTOUR_AREA_MIN = 0;
energy_part_param_.ARMOR_CONTOUR_LENGTH_MIN = 30;
energy_part_param_.ARMOR_CONTOUR_WIDTH_MIN = 15;
energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX = 50;
energy_part_param_.ARMOR_CONTOUR_WIDTH_MAX = 45;
energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX = 3;
energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN = 1;
energy_part_param_.ARMOR_CONTOUR_AREA_RATIO_MIN = 0.7;
energy_part_param_.CENTER_R_CONTOUR_AREA_MAX = 100000;
energy_part_param_.CENTER_R_CONTOUR_AREA_MIN = 0;
@@ -98,13 +121,24 @@ void Energy::initEnergyPartParam() {
energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX = 30;
energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 3;
energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN = 1;
energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.7;
energy_part_param_.FLOW_LIGHT_CONTOUR_HW_RATIO_MIN = 6;
energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX = 17000;
energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN = 0;
energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 90;
energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 35;
energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX = 140;
energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 60;
energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX = 3;
energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 1;
energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MAX = 0.55;
energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN = 0.25;
energy_part_param_.TWIN_ANGEL_MAX = 10;
energy_part_param_.INTERSETION_CONTOUR_AREA_MIN = 60;
energy_part_param_.TARGET_CHANGE_DISTANCE_MAX = 20;
energy_part_param_.TWIN_POINT_MAX = 20;
}

View File

@@ -68,7 +68,7 @@ int Energy::findArmor(const cv::Mat src, int &last_armors_cnt) {
std::vector<vector<Point> > armor_contours_external;//用总轮廓减去外轮廓,只保留内轮廓,除去流动条的影响。
StructingElementErodeDilate(src_bin);//图像膨胀,防止图像断开并更方便寻找
// imshow("armor struct",src_bin);
imshow("armor struct",src_bin);
findContours(src_bin, armor_contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
findContours(src_bin, armor_contours_external, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
@@ -156,6 +156,48 @@ int Energy::findCenterR(const cv::Mat src) {
//----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断找到的矩形候选区是否为扇叶
// ---------------------------------------------------------------------------------------------------------------------
int Energy::findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt){
if (src.empty())return 0;
static Mat src_bin;
src_bin = src.clone();
// threshold(src, src_bin, energy_part_param_.FAN_GRAY_THRESH, 255, THRESH_BINARY);
if(src.type() == CV_8UC3){
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
}
std::vector<vector<Point> > flow_strip_contours;
StructingElementClose(src_bin,6,6);//图像膨胀,防止图像断开并更方便寻找
imshow("flow_strip struct",src_bin);
findContours(src_bin, flow_strip_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (auto &flow_strip_contour : flow_strip_contours) {
if (!isValidFlowStripContour(flow_strip_contour)) {
continue;
}
flow_strips.emplace_back(flow_strip_contour);
// RotatedRect cur_rect = minAreaRect(flow_strip_contour);
// Size2f cur_size = cur_rect.size;
// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width;
// float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width;
// if(length>20&&width>20){
// cout<<cur_rect.center;
// flow_strips.emplace_back(flow_strip_contour);
// cout<<"flow_strip area: "<<length<<'\t'<<width<<endl;
// }
}
if(flow_strips.size() < last_flow_strips_cnt){
last_flow_strips_cnt = static_cast<int>(flow_strips.size());
return -1;//寻找到的流动条比上一帧少,说明该帧有误,返回-1
}
last_flow_strips_cnt = static_cast<int>(flow_strips.size());
return static_cast<int>(flow_strips.size());
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断找到的矩形候选区是否为扇叶
@@ -189,7 +231,7 @@ bool Energy::isValidFanContour(const vector<cv::Point> fan_contour) {
return false;
//长宽比不合适
}
if (cur_contour_area / cur_size.area() < 0.6) return false;//轮廓对矩形的面积占有率不合适
if (cur_contour_area / cur_size.area() < energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN) return false;//轮廓对矩形的面积占有率不合适
return true;
}
@@ -230,7 +272,7 @@ bool Energy::isValidArmorContour(const vector<cv::Point> armor_contour) {
return false;
//长宽比不合适
}
if (cur_contour_area / cur_size.area() < 0.7) return false;//轮廓对矩形的面积占有率不合适
if (cur_contour_area / cur_size.area() < energy_part_param_.ARMOR_CONTOUR_AREA_RATIO_MIN) return false;//轮廓对矩形的面积占有率不合适
return true;
}
@@ -270,6 +312,50 @@ bool Energy::isValidCenterRContour(const vector<cv::Point> center_R_contour) {
return false;
//长宽比不合适
}
if (cur_contour_area / cur_size.area() < 0.7) return false;//轮廓对矩形的面积占有率不合适
if (cur_contour_area / cur_size.area() < energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN) return false;//轮廓对矩形的面积占有率不合适
return true;
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断找到的矩形候选区是否为流动条
// ---------------------------------------------------------------------------------------------------------------------
bool Energy::isValidFlowStripContour(const vector<cv::Point> flow_strip_contour) {
double cur_contour_area = contourArea(flow_strip_contour);
if (cur_contour_area > energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX ||
cur_contour_area < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN)
{
//cout<<cur_contour_area<<" "<<energy_fan_param_.CONTOUR_AREA_MIN<<" "<<energy_fan_param_.CONTOUR_AREA_MAX<<endl;
//cout<<"area fail."<<endl;
return false;
//选区面积大小不合适
}
RotatedRect cur_rect = minAreaRect(flow_strip_contour);
Size2f cur_size = cur_rect.size;
float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width;//将矩形的长边设置为长
float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width;//将矩形的短边设置为宽
if (length < energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN
|| width < energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN
||length > energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX
||width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX)
{
//cout<<"length width fail."<<endl;
return false;
//矩形边长不合适
}
float length_width_ratio = length / width;//计算矩形长宽比
if (length_width_ratio > energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX ||
length_width_ratio < energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN)
{
//cout<<"length width ratio fail."<<endl;
return false;
//长宽比不合适
}
if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN
|| cur_contour_area / cur_size.area() > energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MAX) return false;
//轮廓对矩形的面积占有率不合适
return true;
}

View File

@@ -92,3 +92,25 @@ void Energy::findTargetByIntersection() {
i++;
}
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数在流动条区域内寻找装甲板
// ---------------------------------------------------------------------------------------------------------------------
bool Energy::findTargetInFlowStrip(){
int i = 0;
for(i=0; i<armors.size(); ++i){
std::vector<cv::Point2f> intersection;
if(rotatedRectangleIntersection(armors.at(i).rect, flow_strips.at(0).rect, intersection)==0)
continue;//返回0表示没有重合面积
double cur_contour_area = contourArea(intersection);
if(cur_contour_area < energy_part_param_.INTERSETION_CONTOUR_AREA_MIN)
continue;
else{
target_point = armors.at(i).rect.center;
return true;
}
}
return false;
}

View File

@@ -77,49 +77,47 @@ int Energy::runBig(cv::Mat &gimble_src){
fans.clear();
armors.clear();
centerRs.clear();
flow_strips.clear();
fan_polar_angle.clear();
armor_polar_angle.clear();
changeMark();
if (isMark)return 0;
imagePreprocess(gimble_src);
imshow("img_preprocess", gimble_src);
// imagePreprocess(gimble_src);
// imshow("img_preprocess", gimble_src);
threshold(gimble_src, gimble_src, energy_part_param_.GRAY_THRESH, 255, THRESH_BINARY);
imshow("bin",gimble_src);
fans_cnt = findFan(gimble_src, last_fans_cnt);
// cout<<"fans_cnt: "<<fans_cnt<<endl;
if(fans_cnt==-1) return 0;//滤去漏判的帧
// if(fans_cnt>0)showFanContours("fan",src);
armors_cnt = findArmor(gimble_src, last_armors_cnt);
// cout<<"armors_cnt: "<<armors_cnt<<endl;
if(armors_cnt==-1) return 0;//滤去漏判的帧
// if(armors_cnt>0) showArmorContours("armor",gimble_src);
if (energy_rotation_init) {
initRotation();
return 0;
}
if(armors_cnt != fans_cnt+1) return 0;
getAllArmorCenters();
circleLeastFit();
flow_strips_cnt = findFlowStrip(gimble_src, last_flow_strips_cnt);
if(flow_strips_cnt == 1 && findTargetInFlowStrip()){
showFlowStripContours("strip", gimble_src);
}else{
fans_cnt = findFan(gimble_src, last_fans_cnt);
if(fans_cnt==-1) return 0;//滤去漏判的帧
if(armors_cnt==-1) return 0;//滤去漏判的帧
if(armors_cnt != fans_cnt+1) return 0;
findTargetByIntersection();
// getFanPolarAngle();
// getArmorPolarAngle();
// findTargetByPolar();
// if(armors_cnt>0||fans_cnt>0) showBothContours("Both", gimble_src);
}
centerRs_cnt = findCenterR(gimble_src);
// if(centerRs_cnt>0)showCenterRContours("R", gimble_src);
writeDownMark();
getAllArmorCenters();
circleLeastFit();
// attack_distance = ATTACK_DISTANCE;
getFanPolarAngle();
getArmorPolarAngle();
findTargetByPolar();
// findTargetByIntersection();
if(armors_cnt>0||fans_cnt>0) showBothContours("Both", gimble_src);
if (energy_rotation_init) {
initRotation();
return 0;
}
getPredictPoint();
gimbleRotation();
if(changeTarget())target_cnt++;

View File

@@ -133,9 +133,41 @@ void Energy::showCenterRContours(std::string windows_name, const cv::Mat src) {
imshow(windows_name, image2show);
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数用于显示图像中所有扇叶和装甲板
// 此函数用于显示图像中所有流动条
// ---------------------------------------------------------------------------------------------------------------------
void Energy::showFlowStripContours(std::string windows_name, const cv::Mat src) {
if (src.empty())return;
static Mat image2show;
if(src.type() == CV_8UC1) // 黑白图像
{
cvtColor(src, image2show, COLOR_GRAY2RGB);
} else if (src.type() == CV_8UC3) //RGB 彩色
{
image2show = src.clone();
}
for (const auto &flow_strip : flow_strips)
{
Point2f vertices[4]; //定义矩形的4个顶点
flow_strip.rect.points(vertices); //计算矩形的4个顶点
for (int i = 0; i < 4; i++)
line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(127, 127, 255), 2);
}
for (const auto &armor : armors)
{
if(pointDistance(armor.rect.center, target_point) < energy_part_param_.TWIN_POINT_MAX){
Point2f vertices[4]; //定义矩形的4个顶点
armor.rect.points(vertices); //计算矩形的4个顶点
for (int i = 0; i < 4; i++)
line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(255, 255, 0), 2);
}
}
imshow(windows_name, image2show);
}

View File

@@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
video_gimble = new CameraWrapper(0/*, "armor"*/);
video_chassis = new CameraWrapper(1/*, "energy"*/);
} else {
video_gimble = new VideoWrapper("/home/sun/项目/energy_video/official_r_l.mp4");
video_gimble = new VideoWrapper("/home/sun/项目/energy_video/energy_test.avi");
video_chassis = new VideoWrapper("/home/sun/项目/energy_video/energy_test.avi");
}
if (video_gimble->init()) {
@@ -118,7 +118,7 @@ int main(int argc, char *argv[]) {
energy.runBig(gimble_src);
}
}
cv::waitKey(100);
cv::waitKey(3);
});
} while (ok);