Wip setream carving
This commit is contained in:
parent
438c9d726c
commit
f5dad284e6
11 changed files with 287 additions and 387 deletions
273
seamcarving.cpp
273
seamcarving.cpp
|
|
@ -1,253 +1,63 @@
|
|||
#include "seamcarving.h"
|
||||
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <iostream>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <filesystem>
|
||||
#endif
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
#include "log.h"
|
||||
|
||||
SeamCarving::SeamCarving(const cv::Mat &img, int seams, bool grow) :
|
||||
image(img), seams(seams), grow(grow) {}
|
||||
|
||||
void SeamCarving::init()
|
||||
bool SeamCarving::strechImage(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect)
|
||||
{
|
||||
cv::Mat newFrame = image.clone();
|
||||
|
||||
for(int i = 0; i < seams; i++)
|
||||
{
|
||||
Log(Log::DEBUG)<<"Seam "<<i<<" of "<<seams;
|
||||
//Gradient Magnitude for intensity of image.
|
||||
cv::Mat gradientMagnitude = computeGradientMagnitude(newFrame);
|
||||
cv::Mat gradientMagnitude = computeGradientMagnitude(image);
|
||||
//Use DP to create the real energy map that is used for path calculation.
|
||||
// Strictly using vertical paths for testing simplicity.
|
||||
cv::Mat pathIntensityMat = computePathIntensityMat(gradientMagnitude);
|
||||
|
||||
if(pathIntensityMat.rows == 0 && pathIntensityMat.cols == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
||||
std::vector<int> seam = getLeastImportantPath(pathIntensityMat);
|
||||
vecSeams.push_back(seam);
|
||||
if(seamsVect)
|
||||
seamsVect->push_back(seam);
|
||||
|
||||
newFrame = removeLeastImportantPath(newFrame,seam);
|
||||
|
||||
if(newFrame.rows == 0 && newFrame.cols == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (grow)
|
||||
{
|
||||
cv::Mat growMat = image.clone();
|
||||
|
||||
for (int i = 0; i < vecSeams.size(); i++)
|
||||
{
|
||||
growMat = addLeastImportantPath(growMat,vecSeams[i]);
|
||||
}
|
||||
finalImage = growMat;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalImage = newFrame;
|
||||
}
|
||||
|
||||
sliderPos = seams;
|
||||
|
||||
}
|
||||
|
||||
void SeamCarving::computeNewFinalImage(int sliderPos)
|
||||
{
|
||||
if(sliderPos == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
return;
|
||||
}
|
||||
if(sliderPos < 1 || sliderPos >= sliderMax-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(sliderPos > vecSeams.size())
|
||||
{
|
||||
cv::Mat newFrame = finalImage.clone();
|
||||
for(int i = vecSeams.size()-1; i < sliderPos; i++)
|
||||
{
|
||||
//Gradient Magnitude for intensity of image.
|
||||
cv::Mat gradientMagnitude = computeGradientMagnitude(newFrame);
|
||||
//Use DP to create the real energy map that is used for path calculation.
|
||||
// Strictly using vertical paths for testing simplicity.
|
||||
cv::Mat pathIntensityMat = computePathIntensityMat(gradientMagnitude);
|
||||
|
||||
if(pathIntensityMat.rows == 0 && pathIntensityMat.cols == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
break;
|
||||
}
|
||||
std::vector<int> seam = getLeastImportantPath(pathIntensityMat);
|
||||
vecSeams.push_back(seam);
|
||||
newFrame = removeLeastImportantPath(newFrame,seam);
|
||||
if(newFrame.rows == 0 && newFrame.cols == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (grow)
|
||||
{
|
||||
cv::Mat growMat = image.clone();
|
||||
|
||||
for (int i = 0; i < vecSeams.size(); i++)
|
||||
{
|
||||
growMat = addLeastImportantPath(growMat,vecSeams[i]);
|
||||
}
|
||||
|
||||
finalImage = growMat;
|
||||
}
|
||||
if(!grow)
|
||||
image = removeLeastImportantPath(image, seam);
|
||||
else
|
||||
{
|
||||
finalImage = newFrame;
|
||||
}
|
||||
}
|
||||
else if (sliderPos < vecSeams.size())
|
||||
{
|
||||
cv::Mat newFrame = image.clone();
|
||||
for(int i = 0; i < sliderPos; i++) // TODO check if it is faster to add seams back (probably not)
|
||||
{
|
||||
image = addLeastImportantPath(image, seam);
|
||||
|
||||
if (grow)
|
||||
{
|
||||
newFrame = addLeastImportantPath(newFrame,vecSeams[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
newFrame = removeLeastImportantPath(newFrame,vecSeams[i]);
|
||||
}
|
||||
|
||||
if(newFrame.rows == 0 && newFrame.cols == 0)
|
||||
{
|
||||
finalImage = image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
finalImage = newFrame;
|
||||
if(image.rows == 0 && image.cols == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const cv::Mat& SeamCarving::getFinalImage()
|
||||
bool SeamCarving::strechImageVert(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect)
|
||||
{
|
||||
return finalImage;
|
||||
image = image.t();
|
||||
bool ret = strechImage(image, seams, grow, seamsVect);
|
||||
image = image.t();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SeamCarving::showSeamsImg()
|
||||
bool SeamCarving::strechImageWithSeamsImage(cv::Mat& image, cv::Mat& seamsImage, int seams, bool grow)
|
||||
{
|
||||
cv::Mat seamsFrame = image.clone();
|
||||
//std::cout << "sliderPos: " << sliderPos << std::endl;
|
||||
for(int i = 0; i < sliderPos; i++)
|
||||
{
|
||||
seamsFrame = drawSeam(seamsFrame, vecSeams[i]);
|
||||
}
|
||||
cv::imwrite("output/seams_image.jpg", seamsFrame);
|
||||
cv::imshow( "Image Seams", seamsFrame);
|
||||
}
|
||||
std::vector<std::vector<int>> seamsVect;
|
||||
seamsImage = image.clone();
|
||||
|
||||
static void onChange( int pos, void* object )
|
||||
{
|
||||
SeamCarving* sc = (SeamCarving*)(object);
|
||||
/*if(sc->getBlockUpdateStatus()) {
|
||||
return;
|
||||
}*/
|
||||
sc->computeNewFinalImage(pos);
|
||||
imshow("Final Image", sc->getFinalImage());
|
||||
#if DEBUG
|
||||
sc->showSeamsImg();
|
||||
#endif
|
||||
}
|
||||
static void onMouse( int event, int x, int y, int, void* object)
|
||||
{
|
||||
SeamCarving* sc = (SeamCarving*)(object);
|
||||
if( event == cv::EVENT_LBUTTONDOWN ||
|
||||
event == cv::EVENT_RBUTTONDOWN ||
|
||||
event == cv::EVENT_MBUTTONDOWN
|
||||
)
|
||||
{
|
||||
sc->setBlockUpdate(true);
|
||||
}
|
||||
else if(event == cv::EVENT_LBUTTONUP ||
|
||||
event == cv::EVENT_RBUTTONUP ||
|
||||
event == cv::EVENT_MBUTTONUP)
|
||||
{
|
||||
sc->setBlockUpdate(false);
|
||||
}
|
||||
}
|
||||
bool ret = SeamCarving::strechImage(image, seams, grow, &seamsVect);
|
||||
if(!ret)
|
||||
return false;
|
||||
|
||||
void SeamCarving::setBlockUpdate(bool bUpdate)
|
||||
{
|
||||
blockUpdate = bUpdate;
|
||||
}
|
||||
|
||||
bool SeamCarving::getBlockUpdateStatus()
|
||||
{
|
||||
return blockUpdate;
|
||||
}
|
||||
|
||||
void SeamCarving::showImage()
|
||||
{
|
||||
#if __cplusplus >= 201703L
|
||||
if(!std::filesystem::exists("output"))
|
||||
{
|
||||
std::filesystem::create_directory("output");
|
||||
}
|
||||
#endif
|
||||
if( image.empty() )
|
||||
{
|
||||
std::cout << "Could not open raw image" << std::endl ;
|
||||
return;
|
||||
}
|
||||
namedWindow( "Raw Image", cv::WINDOW_AUTOSIZE );
|
||||
cv::imshow( "Raw Image", image );
|
||||
|
||||
if( finalImage.empty() )
|
||||
{
|
||||
std::cout << "Could not open final image" << std::endl ;
|
||||
return;
|
||||
}
|
||||
#if DEBUG
|
||||
namedWindow( "gradient Image", cv::WINDOW_AUTOSIZE );
|
||||
cv::Mat gradient = computeGradientMagnitude(image);
|
||||
cv::Mat u8_image;
|
||||
gradient.convertTo(u8_image, CV_8U);
|
||||
|
||||
cv::imwrite("output/gradient_image.jpg", u8_image);
|
||||
cv::imshow("gradient Image", u8_image);
|
||||
|
||||
namedWindow( "intensity Image", cv::WINDOW_AUTOSIZE );
|
||||
cv::Mat u8_image2;
|
||||
cv::Mat intensityMat = computePathIntensityMat(gradient);
|
||||
cv::Mat dst;
|
||||
cv::normalize(intensityMat, dst, 0, 255, cv::NORM_MINMAX);
|
||||
dst.convertTo(u8_image2, CV_8U);
|
||||
cv::imwrite("output/intensity_image.jpg", u8_image2);
|
||||
cv::imshow( "intensity Image", u8_image2);
|
||||
|
||||
//cv::Mat engImg = GetEnergyImg(image);
|
||||
//namedWindow("energy Image", cv::WINDOW_AUTOSIZE);
|
||||
//cv::Mat u8_image3;
|
||||
//engImg.convertTo(u8_image3, CV_8U);
|
||||
//cv::imshow( "energy Image", u8_image3);
|
||||
namedWindow("Image Seams", cv::WINDOW_AUTOSIZE);
|
||||
showSeamsImg();
|
||||
|
||||
#endif
|
||||
|
||||
namedWindow( "Final Image", cv::WINDOW_AUTOSIZE );
|
||||
cv::createTrackbar("Seams", "Final Image", &sliderPos, sliderMax, onChange, this);
|
||||
//cv::setMouseCallback("Final Image", onMouse, this );
|
||||
cv::imwrite("output/final_image.jpg", finalImage);
|
||||
cv::imshow("Final Image", finalImage);
|
||||
cv::waitKey(0);
|
||||
for(size_t i = 0; i < seamsVect.size(); ++i)
|
||||
seamsImage = drawSeam(seamsImage, seamsVect[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
cv::Mat SeamCarving::GetEnergyImg(const cv::Mat &img)
|
||||
|
|
@ -392,9 +202,7 @@ cv::Mat SeamCarving::removeLeastImportantPath(const cv::Mat &original, const std
|
|||
cv::Size size = cv::Size(orgSize.width-1, orgSize.height);
|
||||
cv::Mat newMat = cv::Mat(size, original.type());
|
||||
|
||||
unsigned char *rawOrig = original.data;
|
||||
unsigned char *rawOutput = newMat.data;
|
||||
for(int row = 0; row < seam.size(); row++)
|
||||
for(size_t row = 0; row < seam.size(); row++)
|
||||
{
|
||||
removePixel(original, newMat, row, seam[row]);
|
||||
}
|
||||
|
|
@ -460,9 +268,7 @@ cv::Mat SeamCarving::addLeastImportantPath(const cv::Mat &original, const std::v
|
|||
cv::Size size = cv::Size(orgSize.width+1, orgSize.height);
|
||||
cv::Mat newMat = cv::Mat(size, original.type());
|
||||
|
||||
unsigned char *rawOrig = original.data;
|
||||
unsigned char *rawOutput = newMat.data;
|
||||
for(int row = 0; row < seam.size(); row++)
|
||||
for(size_t row = 0; row < seam.size(); row++)
|
||||
{
|
||||
//std::cout << "row: " << row << ", col: " << seam[row] << std::endl;
|
||||
addPixel(original, newMat, row, seam[row]);
|
||||
|
|
@ -518,3 +324,18 @@ void SeamCarving::addPixel(const cv::Mat &original, cv::Mat &outputMat, int row,
|
|||
rawOutput[newRowStart + leftPixel*channels+2] = (unsigned char) ((byte3 + byte3L)/2);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat SeamCarving::drawSeam(const cv::Mat &frame, const std::vector<int> &seam)
|
||||
{
|
||||
cv::Mat retMat = frame.clone();
|
||||
for(int row = 0; row < frame.rows; row++)
|
||||
{
|
||||
for(int col = 0; col < frame.cols; col++)
|
||||
{
|
||||
retMat.at<cv::Vec3b>(row, seam[row])[0] = 0;
|
||||
retMat.at<cv::Vec3b>(row, seam[row])[1] = 255;
|
||||
retMat.at<cv::Vec3b>(row, seam[row])[2] = 0;
|
||||
}
|
||||
}
|
||||
return retMat;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue