diff options
30 files changed, 13 insertions, 1106 deletions
@@ -1,4 +1,4 @@ -straighten-img crop -*.jpg +merge +straighten diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6154bf7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cxxopts"] + path = cxxopts + url = https://github.com/jarro2783/cxxopts @@ -1,9 +1,12 @@ CFLAGS = -lpthread -lstdc++ CFLAGS += `pkg-config --libs opencv` -crop: crop.cpp - g++ $(CFLAGS) crop.cpp -o crop +crop: crop.cc + g++ $(CFLAGS) crop.cc -o crop -straighten-img: straighten-img.cpp - g++ $(CFLAGS) straighten-img.cpp -o straighten-img +merge: merge.cc + g++ -std=c++11 $(CFLAGS) merge.cc -o merge + +straighten: straighten.cc + g++ $(CFLAGS) straighten.cc -o straighten @@ -1,7 +1,2 @@ -OpenCV Code -=========== - ---- - -C++ and Python source code extracted from the tutorials at http://opencv-code.com. +Tools for basic photo editing with OpenCV. diff --git a/assets/README.md b/assets/README.md deleted file mode 100644 index 0cb7056..0000000 --- a/assets/README.md +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains the images and videos used by the code samples in this repository. All files are in public domain or licensed under Creative Commons license. - -Credits -------- - - - [`flughahn.jpg`](http://commons.wikimedia.org/wiki/File:Flughahn.jpg#mediaviewer/File:Flughahn.jpg) by [Beckmannjan](//de.wikipedia.org/wiki/Benutzer:Beckmannjan) via Wikimedia Commons. - - [`The_Chapter_House.jpg`](http://commons.wikimedia.org/wiki/File:Wells_Cathedral_Lady_Chapel,_Somerset,_UK_-_Diliff.jpg#mediaviewer/File:Wells_Cathedral_Lady_Chapel,_Somerset,_UK_-_Diliff.jpg) by [Diliff](//commons.wikimedia.org/wiki/User:Diliff) via Wikimedia Commons. diff --git a/assets/The_Chapter_House.jpg b/assets/The_Chapter_House.jpg Binary files differdeleted file mode 100644 index 927f242..0000000 --- a/assets/The_Chapter_House.jpg +++ /dev/null diff --git a/assets/flughahn.jpg b/assets/flughahn.jpg Binary files differdeleted file mode 100644 index 047b760..0000000 --- a/assets/flughahn.jpg +++ /dev/null diff --git a/assets/lena.jpg b/assets/lena.jpg Binary files differdeleted file mode 100644 index f06aa74..0000000 --- a/assets/lena.jpg +++ /dev/null diff --git a/cxxopts b/cxxopts new file mode 160000 +Subproject d92988c6a218e2fef987e30d99445e7c87c4b87 diff --git a/display-histogram.cpp b/display-histogram.cpp deleted file mode 100644 index 17f5a14..0000000 --- a/display-histogram.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Code sample for displaying image histogram in OpenCV. - */ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iostream> - -using namespace cv; -using namespace std; - -void showHistogram(Mat& img) -{ - int bins = 256; // number of bins - int nc = img.channels(); // number of channels - - vector<Mat> hist(nc); // histogram arrays - - // Initalize histogram arrays - for (int i = 0; i < hist.size(); i++) - hist[i] = Mat::zeros(1, bins, CV_32SC1); - - // Calculate the histogram of the image - for (int i = 0; i < img.rows; i++) - { - for (int j = 0; j < img.cols; j++) - { - for (int k = 0; k < nc; k++) - { - uchar val = nc == 1 ? img.at<uchar>(i,j) : img.at<Vec3b>(i,j)[k]; - hist[k].at<int>(val) += 1; - } - } - } - - // For each histogram arrays, obtain the maximum (peak) value - // Needed to normalize the display later - int hmax[3] = {0,0,0}; - for (int i = 0; i < nc; i++) - { - for (int j = 0; j < bins-1; j++) - hmax[i] = hist[i].at<int>(j) > hmax[i] ? hist[i].at<int>(j) : hmax[i]; - } - - const char* wname[3] = { "blue", "green", "red" }; - Scalar colors[3] = { Scalar(255,0,0), Scalar(0,255,0), Scalar(0,0,255) }; - - vector<Mat> canvas(nc); - - // Display each histogram in a canvas - for (int i = 0; i < nc; i++) - { - canvas[i] = Mat::ones(125, bins, CV_8UC3); - - for (int j = 0, rows = canvas[i].rows; j < bins-1; j++) - { - line( - canvas[i], - Point(j, rows), - Point(j, rows - (hist[i].at<int>(j) * rows/hmax[i])), - nc == 1 ? Scalar(200,200,200) : colors[i], - 1, 8, 0 - ); - } - - imshow(nc == 1 ? "value" : wname[i], canvas[i]); - } -} - -// Test the `showHistogram()` function above -int main() -{ - Mat src = imread("c:/users/nash/desktop/assets/lena.jpg"); - if (src.empty()) - return -1; - showHistogram(src); - imshow("src", src); - waitKey(0); - return 0; -} - diff --git a/display-histogram.py b/display-histogram.py deleted file mode 100644 index 0f0fedd..0000000 --- a/display-histogram.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python - -""" -Sample code for displaying image histogram with Matplotlib -""" - -import cv2 -import matplotlib.pyplot as plt - -def show_histogram(im): - """ Function to display image histogram. - Supports single and three channel images. """ - if im.ndim == 2: - # Input image is single channel - plt.hist(im.flatten(), 256, range=(0,250), fc='k') - plt.show() - elif im.ndim == 3: - # Input image is three channels - fig = plt.figure() - fig.add_subplot(311) - plt.hist(im[...,0].flatten(), 256, range=(0,250), fc='b') - fig.add_subplot(312) - plt.hist(im[...,1].flatten(), 256, range=(0,250), fc='g') - fig.add_subplot(313) - plt.hist(im[...,2].flatten(), 256, range=(0,250), fc='r') - plt.show() - -if __name__ == '__main__': - im = cv2.imread("lena.jpg"); - if not (im == None): - show_histogram(im) - - diff --git a/eye-tracking.cpp b/eye-tracking.cpp deleted file mode 100644 index ae5cdfd..0000000 --- a/eye-tracking.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/** - * eye-tracking.cpp: - * Eye detection and tracking with OpenCV - * - * This program tries to detect and tracking the user's eye with webcam. - * At startup, the program performs face detection followed by eye detection - * using OpenCV's built-in Haar cascade classifier. If the user's eye detected - * successfully, an eye template is extracted. This template will be used in - * the subsequent template matching for tracking the eye. - */ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <opencv2/objdetect/objdetect.hpp> - -cv::CascadeClassifier face_cascade; -cv::CascadeClassifier eye_cascade; - -/** - * Function to detect human face and the eyes from an image. - * - * @param im The source image - * @param tpl Will be filled with the eye template, if detection success. - * @param rect Will be filled with the bounding box of the eye - * @return zero=failed, nonzero=success - */ -int detectEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect) -{ - std::vector<cv::Rect> faces, eyes; - face_cascade.detectMultiScale(im, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(30,30)); - - for (int i = 0; i < faces.size(); i++) - { - cv::Mat face = im(faces[i]); - eye_cascade.detectMultiScale(face, eyes, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(20,20)); - - if (eyes.size()) - { - rect = eyes[0] + cv::Point(faces[i].x, faces[i].y); - tpl = im(rect); - } - } - - return eyes.size(); -} - -/** - * Perform template matching to search the user's eye in the given image. - * - * @param im The source image - * @param tpl The eye template - * @param rect The eye bounding box, will be updated with the new location of the eye - */ -void trackEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect) -{ - cv::Size size(rect.width * 2, rect.height * 2); - cv::Rect window(rect + size - cv::Point(size.width/2, size.height/2)); - - window &= cv::Rect(0, 0, im.cols, im.rows); - - cv::Mat dst(window.width - tpl.rows + 1, window.height - tpl.cols + 1, CV_32FC1); - cv::matchTemplate(im(window), tpl, dst, CV_TM_SQDIFF_NORMED); - - double minval, maxval; - cv::Point minloc, maxloc; - cv::minMaxLoc(dst, &minval, &maxval, &minloc, &maxloc); - - if (minval <= 0.2) - { - rect.x = window.x + minloc.x; - rect.y = window.y + minloc.y; - } - else - rect.x = rect.y = rect.width = rect.height = 0; -} - -int main(int argc, char** argv) -{ - // Load the cascade classifiers - // Make sure you point the XML files to the right path, or - // just copy the files from [OPENCV_DIR]/data/haarcascades directory - face_cascade.load("haarcascade_frontalface_alt2.xml"); - eye_cascade.load("haarcascade_eye.xml"); - - // Open webcam - cv::VideoCapture cap(0); - - // Check if everything is ok - if (face_cascade.empty() || eye_cascade.empty() || !cap.isOpened()) - return 1; - - // Set video to 320x240 - cap.set(CV_CAP_PROP_FRAME_WIDTH, 320); - cap.set(CV_CAP_PROP_FRAME_HEIGHT, 240); - - cv::Mat frame, eye_tpl; - cv::Rect eye_bb; - - while (cv::waitKey(15) != 'q') - { - cap >> frame; - if (frame.empty()) - break; - - // Flip the frame horizontally, Windows users might need this - cv::flip(frame, frame, 1); - - // Convert to grayscale and - // adjust the image contrast using histogram equalization - cv::Mat gray; - cv::cvtColor(frame, gray, CV_BGR2GRAY); - - if (eye_bb.width == 0 && eye_bb.height == 0) - { - // Detection stage - // Try to detect the face and the eye of the user - detectEye(gray, eye_tpl, eye_bb); - } - else - { - // Tracking stage with template matching - trackEye(gray, eye_tpl, eye_bb); - - // Draw bounding rectangle for the eye - cv::rectangle(frame, eye_bb, CV_RGB(0,255,0)); - } - - // Display video - cv::imshow("video", frame); - } - - return 0; -} - diff --git a/opencv-qt-integration-1/ImageViewer.cpp b/opencv-qt-integration-1/ImageViewer.cpp deleted file mode 100644 index 780f221..0000000 --- a/opencv-qt-integration-1/ImageViewer.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include <QtWidgets> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include "ImageViewer.h" - -ImageViewer::ImageViewer() -{ - img = cv::imread("../assets/flughahn.jpg"); - - imageLabel = new QLabel(); - if (img.empty()) { - imageLabel->setText("Cannot load the input image!"); - } else { - cv::cvtColor(img, img, cv::COLOR_BGR2RGB); - QImage _img(img.data, img.cols, img.rows, QImage::Format_RGB888); - imageLabel->setPixmap(QPixmap::fromImage(_img)); - } - - quitButton = new QPushButton("Quit"); - connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); - - mainLayout = new QVBoxLayout(); - mainLayout->addWidget(imageLabel); - mainLayout->addWidget(quitButton); - - setLayout(mainLayout); - setWindowTitle("OpenCV - Qt Integration"); -} diff --git a/opencv-qt-integration-1/ImageViewer.h b/opencv-qt-integration-1/ImageViewer.h deleted file mode 100644 index e07c333..0000000 --- a/opencv-qt-integration-1/ImageViewer.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef IMAGEVIEWER_H -#define IMAGEVIEWER_H - -#include <opencv2/core/core.hpp> -#include <QWidget> - -class QLabel; -class QVBoxLayout; -class QPushButton; - -class ImageViewer : public QWidget -{ -public: - ImageViewer(); - -private: - cv::Mat img; - QLabel *imageLabel; - QVBoxLayout *mainLayout; - QPushButton *quitButton; -}; - -#endif diff --git a/opencv-qt-integration-1/ImageViewer.pro b/opencv-qt-integration-1/ImageViewer.pro deleted file mode 100644 index 0614934..0000000 --- a/opencv-qt-integration-1/ImageViewer.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = app -TARGET = ImageViewer -INCLUDEPATH += . -QT += widgets - -# Input -HEADERS += ImageViewer.h -SOURCES += ImageViewer.cpp main.cpp -INCLUDEPATH += /usr/local/include -LIBS += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs diff --git a/opencv-qt-integration-1/README.md b/opencv-qt-integration-1/README.md deleted file mode 100644 index e0200ae..0000000 --- a/opencv-qt-integration-1/README.md +++ /dev/null @@ -1,41 +0,0 @@ -OpenCV - Qt Integration -======================= - -This code sample shows the basics to display OpenCV's matrix (`cv::Mat`) within a Qt GUI. The code simply load the `flughahn.jpg` image from the `assets/` directory and display it using the `QLabel` widget. - -![Screenshot](http://i.imgur.com/k1et0FY.png) - -Within the `python/` directory, you will see the same code written in Python. - -To compile and run the code, you need to have Qt 5 installed on your computer. The code is successfully tested on the following environment: - - - Mac OS X Mavericks - - Qt 5.3.0 - - OpenCV 3.0.0 - - Python 3.4.1 - -Compiling ---------- - -Open `ImageViewer.pro` and modify the variables to match with your system. For example, you might need to modify the paths for the includes and libraries especially if you're on Windows. - - INCLUDEPATH += /usr/local/include - LIBS += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs - -Change your working directory and compile the code by typing: - - qmake - make - -If everything is ok, it will produce an executable: `ImageViewer` (Linux), `ImageViewer.exe` (Windows), or `ImageViewer.app` (Mac). Run the executable and you will see the GUI like the screenshot above. - -Known Issues ------------- - -In `ImageViewer.cpp`, the code using relative path to locate the input image: - - img = cv::imread("../assets/flughahn.jpg"); - -If the program cannot display the image and shows the "Cannot load the input image!" warning, try to use absolute path instead. For example: - - img = cv::imread("/full/path/to/flughahn.jpg"); diff --git a/opencv-qt-integration-1/main.cpp b/opencv-qt-integration-1/main.cpp deleted file mode 100644 index 0993f8c..0000000 --- a/opencv-qt-integration-1/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include <QApplication> -#include "ImageViewer.h" - -int main(int argc, char** argv) -{ - QApplication app(argc, argv); - ImageViewer viewer; - viewer.show(); - app.exec(); -} diff --git a/opencv-qt-integration-1/python/ImageViewer.py b/opencv-qt-integration-1/python/ImageViewer.py deleted file mode 100644 index 1525f21..0000000 --- a/opencv-qt-integration-1/python/ImageViewer.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import os -import sys - -try: - from PyQt5.QtCore import * - from PyQt5.QtGui import * - from PyQt5.QtWidgets import * - import cv2 -except ImportError: - print("Please install the required packages.") - sys.exit() - -class ImageViewer(QWidget): - - def __init__(self): - QWidget.__init__(self) - self.filename = "../../assets/flughahn.jpg" - self.setup_ui() - - def setup_ui(self): - img = cv2.imread(self.filename) - self.image_label = QLabel() - if img is None: - self.image_label.setText("Cannot load the input image.") - else: - img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) - img_ = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888) - self.image_label.setPixmap(QPixmap.fromImage(img_)) - self.quit_button = QPushButton("Quit") - self.quit_button.clicked.connect(self.close) - self.main_layout = QVBoxLayout() - self.main_layout.addWidget(self.image_label) - self.main_layout.addWidget(self.quit_button) - self.setLayout(self.main_layout) - self.setWindowTitle("OpenCV - Qt Integration") - - -if __name__ == "__main__": - app = QApplication(sys.argv) - viewer = ImageViewer() - viewer.show() - app.exec_() diff --git a/opencv-qt-integration-2/ImageApp.cpp b/opencv-qt-integration-2/ImageApp.cpp deleted file mode 100644 index 5833bd8..0000000 --- a/opencv-qt-integration-2/ImageApp.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <QtWidgets> -#include "ImageApp.h" - -ImageApp::ImageApp() -{ - originalImage = cv::imread("../assets/The_Chapter_House.jpg"); - if (originalImage.data) { - cv::cvtColor(originalImage, originalImage, cv::COLOR_BGR2RGB); - } - setupUi(); - showImage(originalImage); -} - -/** - * Setup the widgets - */ -void ImageApp::setupUi() -{ - imageLabel = new QLabel(); - - originalButton = new QPushButton("Original"); - connect(originalButton, SIGNAL(clicked()), this, SLOT(showOriginalImage())); - - blurButton = new QPushButton("Gaussian Blur"); - connect(blurButton, SIGNAL(clicked()), this, SLOT(doGaussianBlur())); - - cannyButton = new QPushButton("Canny"); - connect(cannyButton, SIGNAL(clicked()), this, SLOT(doCanny())); - - quitButton = new QPushButton("Quit"); - connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); - - buttonsLayout = new QVBoxLayout(); - buttonsLayout->addWidget(originalButton); - buttonsLayout->addWidget(blurButton); - buttonsLayout->addWidget(cannyButton); - buttonsLayout->addStretch(); - buttonsLayout->addWidget(quitButton); - - mainLayout = new QHBoxLayout(); - mainLayout->addWidget(imageLabel); - - if (originalImage.data) { - mainLayout->addLayout(buttonsLayout); - } - setLayout(mainLayout); - setWindowTitle("Image Processing with Qt and OpenCV"); -} - -/** - * Redraw original image - */ -void ImageApp::showOriginalImage() -{ - showImage(originalImage); -} - -/** - * Perform Canny edge detection on original image and display the result - */ -void ImageApp::doCanny() -{ - cv::Mat gray; - cv::cvtColor(originalImage, gray, cv::COLOR_RGB2GRAY); - cv::Canny(gray, processedImage, 150, 150); - cv::cvtColor(processedImage, processedImage, cv::COLOR_GRAY2RGB); - showImage(processedImage); -} - -/** - * Perform Gaussian blurring on original image and display the result - */ -void ImageApp::doGaussianBlur() -{ - cv::GaussianBlur(originalImage, processedImage, cv::Size(15, 15), 0, 0); - showImage(processedImage); -} - -/** - * Draw OpenCV matrix using QLabel - */ -void ImageApp::showImage(cv::Mat img) -{ - if (img.data) { - QImage _img(img.data, img.cols, img.rows, QImage::Format_RGB888); - imageLabel->setPixmap(QPixmap::fromImage(_img)); - } else { - imageLabel->setText("Cannot load the input image!"); - } -} diff --git a/opencv-qt-integration-2/ImageApp.h b/opencv-qt-integration-2/ImageApp.h deleted file mode 100644 index bdedb9b..0000000 --- a/opencv-qt-integration-2/ImageApp.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef IMAGEAPP_H -#define IMAGEAPP_H - -#include <opencv2/core/core.hpp> -#include <QWidget> - -class QLabel; -class QVBoxLayout; -class QHBoxLayout; -class QPushButton; - -class ImageApp : public QWidget -{ - Q_OBJECT - -public: - ImageApp(); - -private slots: - void showOriginalImage(); - void doCanny(); - void doGaussianBlur(); - -private: - void setupUi(); - void showImage(cv::Mat); - - cv::Mat originalImage; - cv::Mat processedImage; - QLabel *imageLabel; - QPushButton *originalButton; - QPushButton *blurButton; - QPushButton *cannyButton; - QPushButton *quitButton; - QVBoxLayout *buttonsLayout; - QHBoxLayout *mainLayout; -}; - -#endif diff --git a/opencv-qt-integration-2/ImageApp.pro b/opencv-qt-integration-2/ImageApp.pro deleted file mode 100644 index 8a9bb7d..0000000 --- a/opencv-qt-integration-2/ImageApp.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = ImageApp -QT += core widgets -HEADERS += ImageApp.h -SOURCES += ImageApp.cpp main.cpp -INCLUDEPATH += . /usr/local/include -LIBS += -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs diff --git a/opencv-qt-integration-2/README.md b/opencv-qt-integration-2/README.md deleted file mode 100644 index 7c1725b..0000000 --- a/opencv-qt-integration-2/README.md +++ /dev/null @@ -1,41 +0,0 @@ -OpenCV - Qt Integration -======================= - -This code sample shows you how to do basic image manipulation to an image and display the result using the `QLabel` widget. The code loads `The_Chapter_House.jpg` from the `assets/` directory and provides two buttons to perform some basic manipulation. - -![screenshot](http://i.imgur.com/OPCiEw8.png) - -The same program written in Python is available in the `python/` directory. - -To compile and run the code, you need to have Qt 5 installed on your computer. The code is successfully tested on the following environment: - - - Mac OS X Mavericks - - Qt 5.3.0 - - OpenCV 3.0.0 - - Python 3.4.1 - -Compiling ---------- - -Open `ImageApp.pro` and modify the variables to match with your system. For example, you might need to modify the paths for the includes and libraries especially if you're on Windows. - - INCLUDEPATH += /usr/local/include - LIBS += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs - -Change your working directory and compile the code by typing: - - qmake - make - -If everything is ok, it will produce an executable: `ImageApp` (Linux), `ImageApp.exe` (Windows), or `ImageApp.app` (Mac). Run the executable and you will see the GUI like the screenshot above. - -Known Issues ------------- - -In `ImageApp.cpp`, the code using relative path to locate the input image: - - img = cv::imread("../assets/The_Chapter_House.jpg"); - -If the program cannot display the image and shows the "Cannot load the input image!" warning, try to use absolute path instead. For example: - - img = cv::imread("/full/path/to/The_Chapter_House.jpg"); diff --git a/opencv-qt-integration-2/main.cpp b/opencv-qt-integration-2/main.cpp deleted file mode 100644 index 208f75c..0000000 --- a/opencv-qt-integration-2/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include <QApplication> -#include "ImageApp.h" - -int main(int argc, char** argv) -{ - QApplication app(argc, argv); - ImageApp imageApp; - imageApp.show(); - app.exec(); -} diff --git a/opencv-qt-integration-2/python/ImageApp.py b/opencv-qt-integration-2/python/ImageApp.py deleted file mode 100644 index afa00b1..0000000 --- a/opencv-qt-integration-2/python/ImageApp.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import os -import sys - -try: - from PyQt5.QtCore import * - from PyQt5.QtGui import * - from PyQt5.QtWidgets import * - import cv2 -except ImportError: - print("Please install the required modules.") - sys.exit() - - -class ImageApp(QWidget): - - def __init__(self): - QWidget.__init__(self) - self.original_img = cv2.imread("../../assets/The_Chapter_House.jpg") - if self.original_img is not None: - self.original_img = cv2.cvtColor(self.original_img, cv2.COLOR_BGR2RGB) - self.setup_ui() - self.show_image(self.original_img) - - def setup_ui(self): - """Setup the UI widgets.""" - self.image_label = QLabel() - # Setup buttons - self.original_btn = QPushButton("Original") - self.original_btn.clicked.connect(self.show_original_image) - self.blur_btn = QPushButton("Gaussian Blur") - self.blur_btn.clicked.connect(self.do_gaussian_blur) - self.canny_btn = QPushButton("Canny") - self.canny_btn.clicked.connect(self.do_canny) - self.quit_btn = QPushButton("Quit") - self.quit_btn.clicked.connect(self.close) - # Setup layout for buttons - self.buttons_layout = QVBoxLayout() - self.buttons_layout.addWidget(self.original_btn) - self.buttons_layout.addWidget(self.blur_btn) - self.buttons_layout.addWidget(self.canny_btn) - self.buttons_layout.addStretch() - self.buttons_layout.addWidget(self.quit_btn) - # Setup main layout - self.main_layout = QHBoxLayout() - self.main_layout.addWidget(self.image_label) - if self.original_img is not None: - self.main_layout.addLayout(self.buttons_layout) - self.setLayout(self.main_layout) - self.setWindowTitle("Image Processing with Qt and OpenCV") - - def show_original_image(self): - """Redraw original image.""" - self.show_image(self.original_img) - - def do_gaussian_blur(self): - """Perform Canny edge detection on original image and display the result.""" - img = cv2.GaussianBlur(self.original_img, (15, 15), 0, 0) - self.show_image(img) - - def do_canny(self): - """Perform Gaussian blurring on original image and display the result.""" - img = cv2.cvtColor(self.original_img, cv2.COLOR_RGB2GRAY) - img = cv2.Canny(img, 150, 150) - img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) - self.show_image(img) - - def show_image(self, img): - if img is not None: - img_ = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888) - self.image_label.setPixmap(QPixmap.fromImage(img_)) - else: - self.image_label.setText("Cannot load the input image!") - - -if __name__ == "__main__": - app = QApplication(sys.argv) - image_app = ImageApp() - image_app.show() - app.exec_() diff --git a/pupil-detect.cpp b/pupil-detect.cpp deleted file mode 100644 index 6e51c94..0000000 --- a/pupil-detect.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Program to detect pupil, based on - * http://www.codeproject.com/Articles/137623/Pupil-or-Eyeball-Detection-and-Extraction-by-C-fro - * with some improvements. - */ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <cmath> - -int main(int argc, char** argv) -{ - // Load image - cv::Mat src = cv::imread("eye_image.jpg"); - if (src.empty()) - return -1; - - // Invert the source image and convert to grayscale - cv::Mat gray; - cv::cvtColor(~src, gray, CV_BGR2GRAY); - - // Convert to binary image by thresholding it - cv::threshold(gray, gray, 220, 255, cv::THRESH_BINARY); - - // Find all contours - std::vector<std::vector<cv::Point> > contours; - cv::findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); - - // Fill holes in each contour - cv::drawContours(gray, contours, -1, CV_RGB(255,255,255), -1); - - for (int i = 0; i < contours.size(); i++) - { - double area = cv::contourArea(contours[i]); - cv::Rect rect = cv::boundingRect(contours[i]); - int radius = rect.width/2; - - // If contour is big enough and has round shape - // Then it is the pupil - if (area >= 30 && - std::abs(1 - ((double)rect.width / (double)rect.height)) <= 0.2 && - std::abs(1 - (area / (CV_PI * std::pow(radius, 2)))) <= 0.2) - { - cv::circle(src, cv::Point(rect.x + radius, rect.y + radius), radius, CV_RGB(255,0,0), 2); - } - } - - cv::imshow("image", src); - cv::waitKey(0); - - return 0; -} - diff --git a/quad-segmentation.cpp b/quad-segmentation.cpp deleted file mode 100644 index 17428a1..0000000 --- a/quad-segmentation.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Automatic perspective correction for quadrilateral objects. See the tutorial at - * http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/ - */ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iostream> - -cv::Point2f center(0,0); - -cv::Point2f computeIntersect(cv::Vec4i a, - cv::Vec4i b) -{ - int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3], x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3]; - float denom; - - if (float d = ((float)(x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))) - { - cv::Point2f pt; - pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d; - pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; - return pt; - } - else - return cv::Point2f(-1, -1); -} - -void sortCorners(std::vector<cv::Point2f>& corners, - cv::Point2f center) -{ - std::vector<cv::Point2f> top, bot; - - for (int i = 0; i < corners.size(); i++) - { - if (corners[i].y < center.y) - top.push_back(corners[i]); - else - bot.push_back(corners[i]); - } - corners.clear(); - - if (top.size() == 2 && bot.size() == 2){ - cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0]; - cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1]; - cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0]; - cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1]; - - - corners.push_back(tl); - corners.push_back(tr); - corners.push_back(br); - corners.push_back(bl); - } -} - -int main() -{ - cv::Mat src = cv::imread("image.jpg"); - if (src.empty()) - return -1; - - cv::Mat bw; - cv::cvtColor(src, bw, CV_BGR2GRAY); - cv::blur(bw, bw, cv::Size(3, 3)); - cv::Canny(bw, bw, 100, 100, 3); - - std::vector<cv::Vec4i> lines; - cv::HoughLinesP(bw, lines, 1, CV_PI/180, 70, 30, 10); - - // Expand the lines - for (int i = 0; i < lines.size(); i++) - { - cv::Vec4i v = lines[i]; - lines[i][0] = 0; - lines[i][1] = ((float)v[1] - v[3]) / (v[0] - v[2]) * -v[0] + v[1]; - lines[i][2] = src.cols; - lines[i][3] = ((float)v[1] - v[3]) / (v[0] - v[2]) * (src.cols - v[2]) + v[3]; - } - - std::vector<cv::Point2f> corners; - for (int i = 0; i < lines.size(); i++) - { - for (int j = i+1; j < lines.size(); j++) - { - cv::Point2f pt = computeIntersect(lines[i], lines[j]); - if (pt.x >= 0 && pt.y >= 0) - corners.push_back(pt); - } - } - - std::vector<cv::Point2f> approx; - cv::approxPolyDP(cv::Mat(corners), approx, cv::arcLength(cv::Mat(corners), true) * 0.02, true); - - if (approx.size() != 4) - { - std::cout << "The object is not quadrilateral!" << std::endl; - return -1; - } - - // Get mass center - for (int i = 0; i < corners.size(); i++) - center += corners[i]; - center *= (1. / corners.size()); - - sortCorners(corners, center); - if (corners.size() == 0){ - std::cout << "The corners were not sorted correctly!" << std::endl; - return -1; - } - cv::Mat dst = src.clone(); - - // Draw lines - for (int i = 0; i < lines.size(); i++) - { - cv::Vec4i v = lines[i]; - cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0,255,0)); - } - - // Draw corner points - cv::circle(dst, corners[0], 3, CV_RGB(255,0,0), 2); - cv::circle(dst, corners[1], 3, CV_RGB(0,255,0), 2); - cv::circle(dst, corners[2], 3, CV_RGB(0,0,255), 2); - cv::circle(dst, corners[3], 3, CV_RGB(255,255,255), 2); - - // Draw mass center - cv::circle(dst, center, 3, CV_RGB(255,255,0), 2); - - cv::Mat quad = cv::Mat::zeros(300, 220, CV_8UC3); - - std::vector<cv::Point2f> quad_pts; - quad_pts.push_back(cv::Point2f(0, 0)); - quad_pts.push_back(cv::Point2f(quad.cols, 0)); - quad_pts.push_back(cv::Point2f(quad.cols, quad.rows)); - quad_pts.push_back(cv::Point2f(0, quad.rows)); - - cv::Mat transmtx = cv::getPerspectiveTransform(corners, quad_pts); - cv::warpPerspective(src, quad, transmtx, quad.size()); - - cv::imshow("image", dst); - cv::imshow("quadrilateral", quad); - cv::waitKey(); - return 0; -} - diff --git a/shape-detect.cpp b/shape-detect.cpp deleted file mode 100644 index 7d70d08..0000000 --- a/shape-detect.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Simple shape detector program. - * It loads an image and tries to find simple shapes (rectangle, triangle, circle, etc) in it. - * This program is a modified version of `squares.cpp` found in the OpenCV sample dir. - */ -#include <opencv2/highgui/highgui.hpp> -#include <opencv2/imgproc/imgproc.hpp> -#include <cmath> -#include <iostream> - -/** - * Helper function to find a cosine of angle between vectors - * from pt0->pt1 and pt0->pt2 - */ -static double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) -{ - double dx1 = pt1.x - pt0.x; - double dy1 = pt1.y - pt0.y; - double dx2 = pt2.x - pt0.x; - double dy2 = pt2.y - pt0.y; - return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); -} - -/** - * Helper function to display text in the center of a contour - */ -void setLabel(cv::Mat& im, const std::string label, std::vector<cv::Point>& contour) -{ - int fontface = cv::FONT_HERSHEY_SIMPLEX; - double scale = 0.4; - int thickness = 1; - int baseline = 0; - - cv::Size text = cv::getTextSize(label, fontface, scale, thickness, &baseline); - cv::Rect r = cv::boundingRect(contour); - - cv::Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2)); - cv::rectangle(im, pt + cv::Point(0, baseline), pt + cv::Point(text.width, -text.height), CV_RGB(255,255,255), CV_FILLED); - cv::putText(im, label, pt, fontface, scale, CV_RGB(0,0,0), thickness, 8); -} - -int main() -{ - //cv::Mat src = cv::imread("polygon.png"); - cv::Mat src = cv::imread("assets/basic-shapes-2.png"); - if (src.empty()) - return -1; - - // Convert to grayscale - cv::Mat gray; - cv::cvtColor(src, gray, CV_BGR2GRAY); - - // Use Canny instead of threshold to catch squares with gradient shading - cv::Mat bw; - cv::Canny(gray, bw, 0, 50, 5); - - // Find contours - std::vector<std::vector<cv::Point> > contours; - cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - - std::vector<cv::Point> approx; - cv::Mat dst = src.clone(); - - for (int i = 0; i < contours.size(); i++) - { - // Approximate contour with accuracy proportional - // to the contour perimeter - cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true); - - // Skip small or non-convex objects - if (std::fabs(cv::contourArea(contours[i])) < 100 || !cv::isContourConvex(approx)) - continue; - - if (approx.size() == 3) - { - setLabel(dst, "TRI", contours[i]); // Triangles - } - else if (approx.size() >= 4 && approx.size() <= 6) - { - // Number of vertices of polygonal curve - int vtc = approx.size(); - - // Get the cosines of all corners - std::vector<double> cos; - for (int j = 2; j < vtc+1; j++) - cos.push_back(angle(approx[j%vtc], approx[j-2], approx[j-1])); - - // Sort ascending the cosine values - std::sort(cos.begin(), cos.end()); - - // Get the lowest and the highest cosine - double mincos = cos.front(); - double maxcos = cos.back(); - - // Use the degrees obtained above and the number of vertices - // to determine the shape of the contour - if (vtc == 4 && mincos >= -0.1 && maxcos <= 0.3) - setLabel(dst, "RECT", contours[i]); - else if (vtc == 5 && mincos >= -0.34 && maxcos <= -0.27) - setLabel(dst, "PENTA", contours[i]); - else if (vtc == 6 && mincos >= -0.55 && maxcos <= -0.45) - setLabel(dst, "HEXA", contours[i]); - } - else - { - // Detect and label circles - double area = cv::contourArea(contours[i]); - cv::Rect r = cv::boundingRect(contours[i]); - int radius = r.width / 2; - - if (std::abs(1 - ((double)r.width / r.height)) <= 0.2 && - std::abs(1 - (area / (CV_PI * std::pow(radius, 2)))) <= 0.2) - setLabel(dst, "CIR", contours[i]); - } - } - - cv::imshow("src", src); - cv::imshow("dst", dst); - cv::waitKey(0); - return 0; -} - diff --git a/straighten-img.cpp b/straighten.cc index 2b83b85..2b83b85 100644 --- a/straighten-img.cpp +++ b/straighten.cc diff --git a/watershed.cpp b/watershed.cpp deleted file mode 100644 index 64fe039..0000000 --- a/watershed.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Count and segment overlapping objects with Watershed and Distance Transform. - * - * See the tutorial at: - * http://opencv-code.com/count-and-segment-overlapping-objects-with-watershed-and-distance-transform/ - */ -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iostream> - -int main() -{ - cv::Mat src = cv::imread("coins.jpg"); - if (!src.data) - return -1; - - cv::imshow("src", src); - - // Create binary image from source image - cv::Mat bw; - cv::cvtColor(src, bw, CV_BGR2GRAY); - cv::threshold(bw, bw, 40, 255, CV_THRESH_BINARY); - cv::imshow("bw", bw); - - // Perform the distance transform algorithm - cv::Mat dist; - cv::distanceTransform(bw, dist, CV_DIST_L2, 3); - - // Normalize the distance image for range = {0.0, 1.0} - // so we can visualize and threshold it - cv::normalize(dist, dist, 0, 1., cv::NORM_MINMAX); - cv::imshow("dist", dist); - - // Threshold to obtain the peaks - // This will be the markers for the foreground objects - cv::threshold(dist, dist, .5, 1., CV_THRESH_BINARY); - cv::imshow("dist2", dist); - - // Create the CV_8U version of the distance image - // It is needed for cv::findContours() - cv::Mat dist_8u; - dist.convertTo(dist_8u, CV_8U); - - // Find total markers - std::vector<std::vector<cv::Point> > contours; - cv::findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - int ncomp = contours.size(); - - // Create the marker image for the watershed algorithm - cv::Mat markers = cv::Mat::zeros(dist.size(), CV_32SC1); - - // Draw the foreground markers - for (int i = 0; i < ncomp; i++) - cv::drawContours(markers, contours, i, cv::Scalar::all(i+1), -1); - - // Draw the background marker - cv::circle(markers, cv::Point(5,5), 3, CV_RGB(255,255,255), -1); - cv::imshow("markers", markers*10000); - - // Perform the watershed algorithm - cv::watershed(src, markers); - - // Generate random colors - std::vector<cv::Vec3b> colors; - for (int i = 0; i < ncomp; i++) - { - int b = cv::theRNG().uniform(0, 255); - int g = cv::theRNG().uniform(0, 255); - int r = cv::theRNG().uniform(0, 255); - - colors.push_back(cv::Vec3b((uchar)b, (uchar)g, (uchar)r)); - } - - // Create the result image - cv::Mat dst = cv::Mat::zeros(markers.size(), CV_8UC3); - - // Fill labeled objects with random colors - for (int i = 0; i < markers.rows; i++) - { - for (int j = 0; j < markers.cols; j++) - { - int index = markers.at<int>(i,j); - if (index > 0 && index <= ncomp) - dst.at<cv::Vec3b>(i,j) = colors[index-1]; - else - dst.at<cv::Vec3b>(i,j) = cv::Vec3b(0,0,0); - } - } - - cv::imshow("dst", dst); - - cv::waitKey(0); - return 0; -} - |