portfolio/color-space/cvImage.cpp
2026-08-29 23:20:33 +02:00

554 lines
15 KiB
C++

#include "cvImage.h"
//#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
cvImage::cvImage()
: _menu(NULL), _image(NULL)
{
setWindowTitle(tr("Egaliseur de contraste couleur"));
resize(480, 240);
_menu = new QMenu("File");
_menu->addAction("Op3n", this, SLOT(_open()));
_menu->addSeparator();
_menu->addAction("Source", this, SLOT(_rgbView()));
_menu->addSeparator();
_menu->addAction("HSV", this, SLOT(_hsvView()));
_menu->addSeparator();
_menu->addAction("Histograme", this, SLOT(_histcalc()));
_menu->addSeparator();
_menu->addAction("Save", this, SLOT(_save()));
_menu->addSeparator();
_menu->addAction("Exit", this, SLOT(close()));
_menu_bar.addMenu(_menu);
_menu = new QMenu("Egalisation de contraste");
_menu->addAction("Naif", this, SLOT(_egalizeH()));
_menu->addAction("Naif+", this, SLOT(_egalizeH3()));
_menu->addAction("HSU", this, SLOT(_egalizeH2()));
_menu->addSeparator();
_menu->addAction("diff orginal et Naif", this, SLOT(_diff()));
_menu->addAction("diff Naif et Naif+", this, SLOT(_diff1()));
_menu->addAction("diff Naif et HSU", this, SLOT(_diff2()));
_menu_bar.addMenu(_menu);
setMenuBar(&_menu_bar);
_onglet.setParent(this);
// _onglet->tabBar()->setPalette(*(new QPalette(Qt::white)));
setCentralWidget(&_onglet);
}
cvImage::~cvImage()
{
if (_menu)
delete _menu;
if (_image)
delete _image;
}
void cvImage::Mat2QImage(cv::Mat const& src, QImage* dest )
{
cv::Mat temp(src);
cvtColor(src, temp,CV_BGR2RGB);
if (dest)
{
delete dest;
}
dest= new QImage(temp.size().width, temp.size().height, QImage::Format_RGB888);
// Copy cv::Mat to QImage
memcpy(dest->scanLine(0), (unsigned char*)temp.data, dest->width() * dest->height() * temp.channels());
//return dest;
}
void cvImage::QImage2Mat(QImage* const& src, cv::Mat& res)
{
QImage temp = src->copy();
res=cv::Mat(temp.height(),temp.width(),CV_8UC3,(uchar*)temp.bits(),temp.bytesPerLine());
cvtColor(res, res,CV_RGB2BGR);
//return res;
}
void cvImage::paintEvent(QPaintEvent* e)
{
//_onglet->children();
//get the list of tab
//QList<QWidget *> widgets =_onglet->children();
// ajout2->setParent(_onglet);
// _onglet->addTab(ajout,"Visuel");
//_onglet->addTab(ajout1,"Histograme 2D");
// _onglet->addTab(ajout2,"Histogramme 3D");
/* QWidget * widgets = _onglet->widget(0);
QWidget * widgets1 = _onglet->widget(1);
QWidget * widgets2 = _onglet->widget(2);
if(!widgets)
return;
QPainter painter(widgets);
*/
// When no image has been loaded, there's nothing to draw.
if (!_image)
return;
// painter.drawImage(QPoint(0, 0), *_image);
// widgets->resize(_image->size());
_onglet.setImg(_image);
// _onglet->setHist(_hist);
QWidget::paintEvent(e);
}
void cvImage::_open()
{
// Display dialog so the user can select a file
QString filename = QFileDialog::getOpenFileName(this,tr("Open Image"),QDir::currentPath(),tr("Files (*.png *.jpg *.tiff *.bmp *.pgm)"));
if (filename.isEmpty()) // Do nothing if filename is empty
return;
cv::Mat img = cv::imread(filename.toStdString());
if (img.empty())
return;
cvtColor(img, img,CV_BGR2RGB);
_img=img;
// _image is created according to video dimensions
if (_image)
{
delete _image;
}
_image = new QImage(img.size().width, img.size().height, QImage::Format_RGB888);
// Copy cv::Mat to QImage
memcpy(_image->scanLine(0), (unsigned char*)img.data, _image->width() * _image->height() * img.channels());
//Mat2QImage(img, _image);
// Set the filename as the window title
this->statusBar()->setStatusTip(filename);
// Resize the window to fit video dimensions
resize(img.size().width, img.size().height);
// Mouse move events will occur only when a mouse button is pressed down,
// unless mouse tracking has been enabled:
QWidget::setMouseTracking(true);
// Trigger paint event to redraw the window
update();
}
void cvImage::_rgbView()
{
if (_img.empty() ) // pas d'image charger ne rien fair
return;
// l'image exite
if (!_img.empty() && _image)
{
delete _image;
_image = new QImage( _img.data, _img.size().width, _img.size().height, _img.step, QImage::Format_RGB888);
// Resize the window to fit video dimensions
resize(_img.size().width, _img.size().height);
/* cv::Mat rgb,hsv,dst;
cv::cvtColor(_img,rgb,CV_RGB2BGR);
cv::cvtColor(_img,hsv,CV_RGB2HSV);
cv::hconcat(rgb,hsv,dst);
cv::namedWindow( "Source", 1 );
cv::imshow( "Source", dst );
*/ }
update();
}
void cvImage::_hsvView()
{
if (_img.empty() ) // pas d'image charger ne rien fair
return;
// l'image exite
if (!_img.empty() && _image)
{
delete _image;
cv::Mat hsv, hsvI;
cv::cvtColor(_img,hsv,CV_RGB2HSV);
// on permute V et H pour visualisation dans Qimage
// mapage bgr d'onpencv -> permutation pour que les affiche soit corect
cv::vector<cv::Mat> tmp;
cv::split(hsv,tmp);
hsvI=tmp[0];
tmp[0]=tmp[2];
tmp[2]=hsvI;
cv::merge(tmp,hsvI);
cv::namedWindow( "HSV", 1 );
cv::imshow( "HSV", hsv );
_image = new QImage( hsvI.data, hsvI.size().width, hsvI.size().height, hsvI.step, QImage::Format_RGB888);
// Resize the window to fit video dimensions
resize(hsvI.size().width, hsvI.size().height);
update();
}
}
void cvImage::_save()
{
if (_img.empty())
return;
cv::Mat tmp;
cv::cvtColor(_img,tmp,CV_RGB2BGR);
cv::imwrite("src.jpg",tmp);
cv::cvtColor(_img,tmp,CV_RGB2HSV);
cv::imwrite("src_HSV.jpg",tmp);
if (!_img_eq_rgb.empty()){ cv::cvtColor(_img_eq_rgb,tmp,CV_RGB2BGR); cv::imwrite("egalisation_rgb.jpg",tmp);}
if (!_img_eq_rgb1.empty()){ cv::cvtColor(_img_eq_rgb1,tmp,CV_RGB2BGR);; cv::imwrite("egalisation_rgb1.jpg",tmp);}
}
void cvImage::keyPressEvent(QKeyEvent* event)
{
switch (event->key())
{
// ESC: exit application
case Qt::Key_Escape:
{
close();
}
break;
}
}
void cvImage::mouseMoveEvent(QMouseEvent *event)
{
if (!_image)
return;
QPoint pos = event->pos();
if (pos.x() < 10 || pos.x() >= _image->width()+10)
return;
if (pos.y() < 30 || pos.y() >= _image->height()+30)
return;
QString pos_x;
pos_x = pos_x.setNum(pos.x() -10 );
QString pos_y;
pos_y = pos_y.setNum(pos.y()-30);
QColor pixel(_image->pixel(pos_x.toDouble(),pos_y.toDouble()));
int r = pixel.red();
int g = pixel.green();
int b = pixel.blue();
QString pixel_info = pos_x + "," + pos_y +
" R:" + QString().setNum(r) +
" G:" + QString().setNum(g) +
" B:" + QString().setNum(b);
// TODO: set pixel info on status bar instead of window title
this->statusBar()->setStatusTip(pixel_info);
//setWindowTitle(pixel_info);
qDebug() << "cvImage::mouseMoveEvent " << pixel_info;
}
void cvImage::_close()
{
emit closed();
}
/*************************************************
*
*
*
*
*
* ************************************************/
void cvImage::calculHist(cv::Mat& image , int* hist)
{
int i;
/* initialisation de l'histogramme a 0*/
for(i = 0; i < 256;i++)
hist[i]=0;
/* calcule des valeur de l'histogramme */
for(i = 0; i < image.cols*image.rows; i++)
hist[image.data[i]]++;
}
void cvImage::calculHist3(const cv::vector<cv::Mat>& image , int* hist)
{
int i,p;
/* initialisation de l'histogramme a 0*/
for(i = 0; i < 256;i++)
hist[i]=0;
/* calcule des valeur de l'histogramme */
// for(cv::vector<cv::Mat>::iterator i = mv.begin(); i != mv.end();i++)
for(p = 0; p < image[0].cols*image[0].rows; p++)
hist[(image[0].data[p]+image[1].data[p]+image[2].data[p])/3]++;
}
void cvImage::egalizhist(cv::Mat& imSrc, cv::Mat& imDst)
{
int i; double n;
//if (imSrc.size == imDst->size) /* controle des dimention des image*/
// {
int histEg[256],histCum[256];
calculHist(imSrc, histEg);
/*calcule de l'histogramme cumulé*/
for(i=0; i<256; i++)
if(i!=0)
histCum[i]= histCum[i-1] + histEg[i];
else
histCum[i]= histEg[i];
n= (double)histCum[255]; /* nb pixel dans l'image*/
for(i=0; i<256; i++)
histEg[i]= 255* (histCum[i]/n) ;
for(i=0; i< imDst.cols * imDst.rows ; i++)
imDst.data[i]= (uchar ) histEg[ imSrc.data[i] ];
//}
}
void cvImage::egalizhist3(const cv::vector<cv::Mat>& imSrc, cv::vector<cv::Mat>& imDst)
{
int i; double n;
int histEg[256],histCum[256];
calculHist3(imSrc, histEg);
/*calcule de l'histogramme cumulé*/
for(i=0; i<256; i++)
if(i!=0)
histCum[i]= histCum[i-1] + histEg[i];
else
histCum[i]= histEg[i];
n= (double)histCum[255]; /* nb pixel dans l'image*/
for(i=0; i<256; i++)
histEg[i]= 255* (histCum[i]/n) ;
for(i=0; i< imDst[0].cols * imDst[0].rows ; i++){
imDst[0].data[i]= (uchar ) histEg[ imSrc[0].data[i] ];
imDst[1].data[i]= (uchar ) histEg[ imSrc[1].data[i] ];
imDst[2].data[i]= (uchar ) histEg[ imSrc[2].data[i] ];
}
}
void cvImage::_egalizeH()
{
/*
* on egalalise les canneau independament les un des autres
*
*
*/
if (_img.empty())
return;
cv::vector<cv::Mat> mv,v;//[_img.channels()];
cv::split(_img,mv);
for(cv::vector<cv::Mat>::iterator i = mv.begin(); i != mv.end();i++)
egalizhist( *i, *i);
cv::Mat merge;
cv::merge(mv,merge);
_img_eq_rgb=merge;
/*
cv::Mat hsv;
cv::cvtColor(merge,hsv,CV_RGB2HSV);
cv::vector<cv::Mat> mv_tmp;
cv::split(hsv,mv_tmp);
hsv=mv_tmp[0];
mv_tmp[0]=mv_tmp[2];
mv_tmp[2]=hsv;
cv::merge(mv_tmp,hsv);
cv::hconcat(merge,hsv,merge);
*/
if(_image)
delete _image;
_image = new QImage( merge.data,merge.size().width, merge.size().height, merge.step, QImage::Format_RGB888);
_imgHeq1=merge;
// Resize the window to fit video dimensions
resize(merge.size().width, merge.size().height);
update();
}
void cvImage::_egalizeH3()
{
/*
* on egalalise les canneau fonction de l'intensité du pixel i=(r+v+b)/3
*
*
*/
if (_img.empty())
return;
cv::vector<cv::Mat> mv_src, mv_dst;
cv::split(_img,mv_src);
cv::split(_img,mv_dst);
// for(cv::vector<cv::Mat>::iterator i = mv.begin(); i != mv.end();i++)
//egalizhist( *i, *i);
egalizhist3(mv_src,mv_dst);
cv::Mat merge;
cv::merge(mv_dst,merge);
_img_eq_rgb1=merge;
/*
cv::Mat hsv;
cv::cvtColor(merge,hsv,CV_RGB2HSV);
cv::vector<cv::Mat> mv_tmp;
cv::split(hsv,mv_tmp);
hsv=mv_tmp[0];
mv_tmp[0]=mv_tmp[2];
mv_tmp[2]=hsv;
cv::merge(mv_tmp,hsv);
cv::hconcat(merge,hsv,merge);
*///cv::cvtColor(_imBin,imBinair,CV_GRAY2BGR);
if(_image)
delete _image;
_image = new QImage( merge.data,merge.size().width, merge.size().height, merge.step, QImage::Format_RGB888);
_imgHeq1=merge;
// Resize the window to fit video dimensions
resize(merge.size().width, merge.size().height);
update();
}
void cvImage::_egalizeH2(){
if(!_img.data )
return;
cv::Mat src,hsv;
cv::cvtColor(_img, src, CV_RGB2BGR);
cv::cvtColor(src, hsv, CV_BGR2HSV);
// Quantize the hue to 30 levels
// and the saturation to 32 levels
int hbins = 30, sbins = 32;
int histSize[] = {hbins, sbins};
// hue varies from 0 to 179, see cvtColor
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to
// 255 (pure spectrum color)
float sranges[] = { 0, 256 };
const float* ranges[] = { hranges, sranges };
cv::MatND hist;
// we compute the histogram from the 0-th and 1-st channels
int channels[] = {0, 1};
cv::calcHist( &hsv, 1, channels, cv::Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal=0;
cv::minMaxLoc(hist, 0, &maxVal, 0, 0);
int scale = 10;
cv::Mat histImg = cv::Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
cv::rectangle( histImg, cv::Point(h*scale, s*scale),
cv::Point( (h+1)*scale - 1, (s+1)*scale - 1),
cv::Scalar::all(intensity),
CV_FILLED );
}
_image = new QImage( src.data,src.size().width, src.size().height, src.step, QImage::Format_RGB888);
/* cv::namedWindow( "Source", 1 );
cv::imshow( "Source", src );
cv::namedWindow( "H-S Histogram", 1 );
cv::imshow( "H-S Histogram", histImg );
*///waitKey();
}
void cvImage::_histcalc(){
if( !_img.data )
return ;
Mat src, dst;
/// Load image
src = _img;
/// Separate the image in 3 places ( B, G and R )
vector<Mat> bgr_planes;
split( src, bgr_planes );
/// Establish the number of bins
int histSize = 256;
/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat b_hist, g_hist, r_hist;
/// Compute the histograms:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histograms for B, G and R
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
/// Normalize the result to [ 0, histImage.rows ]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// Draw for each channel
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
/// Display
// namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
// imshow("calcHist Demo", histImage );
//_image = new QImage( histImage.data,histImage.size().width, histImage.size().height, histImage.step, QImage::Format_RGB888);
}