Я использую библиотеки OpenCV и SDL2 для приложения C ++.
Opencv используется для захвата кадра с веб-камеры, а затем кадр преобразуется для отображения в окне SDL.SDL используется для захвата входных данных от мыши.
При каждом щелчке в окне SDL в позиции щелчка над рамкой веб-камеры рисуется круг.
Проблема заключается в следующем: при изменении размера окна вручную, когда приложение запущено (из операционной системы, а не из кода), уже нарисованные точки будут отображаться правильно, но если я щелкну левой кнопкой мыши, чтобы нарисовать другую точку в окне с измененным размером, точка будетпостроена полностью за пределами окна.
Это основная функция:
#ifndef __OPENCV__
#define __OPENCV__
#include "opencv2/opencv.hpp"
#endif
#include <iostream>
#include <unistd.h>
#include <vector>
#include <SDL.h>
#include <SDL_events.h>
using namespace cv;
using namespace std;
int mouseCallback(SDL_MouseButtonEvent ev, Mat frame);
int main(int argc, char* argv[])
{
/* Initialise SDL */
if( SDL_Init( SDL_INIT_VIDEO ) < 0)
{
fprintf( stderr, "Could not initialise SDL: %s\n", SDL_GetError() );
exit( -1 );
}
const String sourceReference = argv[1];
int camNum;
string sensorName;
try
{
camNum = stoi(sourceReference); // throws std::length_error
}
catch (const std::exception& e)// reference to the base of a polymorphic object
{
std::cout<<"Exception: " << e.what()<<endl; // information from length_error printed
return -1;
}
cout<<"camera initializing\n";
VideoSettings cam(camNum + CAP_V4L);
cout<<"camera initialized\n";
/* or
VideoCapture captUndTst;
captUndTst.open(sourceCompareWith);*/
cout<<"Ch3ck c4m3ra is 0p3n3d\n";
if ( !cam.isOpened())
{
cout << "Could not open reference " << sourceReference << endl;
return -1;
}
Mat frame;
cam>>frame;
SDL_Window* win = SDL_CreateWindow("Camera", 100, 100, frame.cols, frame.rows,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
SDL_SetWindowTitle(win, "Camera");
SDL_Renderer * renderer = SDL_CreateRenderer(win, -1, 0);
SDL_Event genericEvent;
SDL_Surface* frameSurface;
SDL_Texture* frameTexture;
while(cam.isOpened())
{
while( SDL_PollEvent(&genericEvent) )
{
switch( genericEvent.type )
{
case SDL_MOUSEBUTTONDOWN:
mouseCallback(genericEvent.button, frame);
break;
/* SDL_QUIT event (window close) */
case SDL_QUIT:
return 0;
break;
default:
break;
}
}
cam>>frame;
draw(frame_out);
//Convert to SDL_Surface
frameSurface = SDL_CreateRGBSurfaceFrom((void*)frame_out.data,
frame_out.size().width, frame_out.size().height,
24, frame_out.cols *3,
0xff0000, 0x00ff00, 0x0000ff, 0);
if(frameSurface == NULL)
{
SDL_Log("Couldn't convert Mat to Surface.");
return -2;
}
//Convert to SDL_Texture
frameTexture = SDL_CreateTextureFromSurface(renderer, frameSurface);
if(frameTexture == NULL)
{
SDL_Log("Couldn't convert Mat(converted to surface) to Texture."); //<- ERROR!!
return -1;
}
//imshow("Camera", frame_out);
SDL_RenderCopy(renderer, frameTexture, NULL, NULL);
SDL_RenderPresent(renderer);
/* A delay is needed to show (it actually wait for an input)*/
if(waitKey(delay)>delay){;}
}
SDL_DestroyTexture(frameTexture);
SDL_FreeSurface(frameSurface);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
return 0;
}
int mouseCallback(SDL_MouseButtonEvent ev, Mat frame)
{
if(ev.button == SDL_BUTTON_LEFT)
{
mouseLeft( ev.x, ev.y);
}
}
При нажатии левой кнопки мыши вызываемая функция имеет вид mouseCallback
, вызывающий функцию.mouseLeft
определяется как:
void mouseLeft(int x, int y)
{
Point pt;// = *((Point*)param);
pt.x = x;
pt.y = y;
pts.push_back(pt);
int ii=0;
int size = pts.size()-1;
while(ii<size && size>0)
{
if (euclideanDist(pt, pts.at(ii))<minDistance)
{
//cout<<pts->size()<<endl;
pts.erase (pts.begin()+ii);
// std::vector::end returns an iterator to the element following
//the last element of the container, not to the last element.
pts.erase(pts.end()-1);
size-=2;
}
else
{
;
}
ii++;
}
}
pts
- это вектор точек (изначально он является членом класса, но может быть объявлен глобально для этого примера).Когда вызывается mouseLeft
, если точка щелчка находится достаточно близко к любой точке в pts
, тогда она удаляется из вектора, в противном случае новая точка отталкивается назад.
Функция draw
рисуетточки, хранящиеся в pts
плюс линии, соединяющие точки:
void draw(Mat &frame)
{
vector<Point> new_pts = pts; //avoid modifying the elements we are drawing
int sizeVector = pts.size();
if (sizeVector==1)
{
try
{
circle( frame, pts.at(0), radius, Scalar( 0, 0, 0), FILLED, 8,0);
}
catch (const out_of_range& e)
{
cout<<"Exception with command "<<endl;
cout<<"circle( frame, pts.at(0), radius, Scalar( 0, 0, 0), FILLED, 8,0)"<<endl;
}
}
else
{
int ii=0;
while(ii<(sizeVector-1) && sizeVector>0)
{
try
{
circle( frame, pts.at(ii), radius, Scalar( 0, 0, 0), FILLED, 8,0);
circle( frame, pts.at(ii+1), radius, Scalar( 0, 0, 0), FILLED, 8,0);
line(frame, pts.at(ii), pts.at(ii+1), Scalar( 0, 0, 0 ), 4, 8 );
}
catch (const out_of_range& e)
{
cout<<"Exception with commands: "<<endl;
cout<<"\tcircle( frame, pts.at(ii), radius, Scalar( 0, 0, 0), FILLED, 8,0)"<<endl;
cout<<"\tcircle( frame, pts.at(ii+1), radius, Scalar( 0, 0, 0), FILLED, 8,0);"<<endl;
cout<<"\tline(frame, pts.at(ii), pts.at(ii+1), Scalar( 0, 0, 0 ), 4, 8 );"<<endl;
}
if(pts.size()<=0) break;
ii++;
sizeVector= pts.size();
}
}
}
Та же проблема возникает, если вместо создания окна с SDL_Window* win = SDL_CreateWindow("Camera", 100, 100, frame.cols, frame.rows,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
я удваиваю его размеры, такие как: SDL_Window* win = SDL_CreateWindow("Camera", 100, 100, 2*frame.cols, 2*frame.rows,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
Обратите внимание, что размещенный код является реадаптацией исходного кода, чтобы сделать его простым и понятным.Если что-то отсутствует или неясно, пожалуйста, сообщите мне, чтобы я мог правильно отредактировать вопрос.