Commit 74983e80 authored by bbguimaraes's avatar bbguimaraes
Browse files

image_proc

parent b624f083
......@@ -3,6 +3,8 @@ for details/demos/screenshots.
- asm: simple assembly program that slides a three-digit number across the
terminal and an external seven-segment display.
- image_proc: graphical image processing utility with histograms, equalization,
and filtering.
- mem_manager: best-fit memory allocator simluation.
- nqueens: n-queens solver and graphical display.
- sudoku: Sudoku solver library/GUI using genetic algorithms.
......
Image processing utility. Displays images and their histograms and has options
for equalization and filtering (mean and configurable weight).
# Compilation
The Qt toolkit and opengl are used for the GUI and the compilation can be done
using qmake:
$ qmake
$ make
TEPLATE = app
CONFIG += qt
QT += opengl
QMAKE_CXXFLAGS = -std=c++11
OBJECTS_DIR = obj
MOC_DIR = moc
HEADERS += include/*.h
SOURCES += src/*.cpp
#ifndef CHARTVIEW_H
#define CHARTVIEW_H
#include <QtOpenGL/QGLWidget>
#include <vector>
class ChartView : public QGLWidget {
public:
enum class Mode {LINE, BARS};
ChartView(QWidget * parent = 0);
virtual ~ChartView() {};
void set_data(const std::vector<int> & data);
void set_mode(Mode mode) {this->mode = mode;}
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
private:
void draw_bars();
void draw_line();
std::vector<int> data;
unsigned int max;
Mode mode;
};
#endif // CHARTVIEW_H
#ifndef FILTER_H
#define FILTER_H
#include <QImage>
class Filter {
public:
virtual ~Filter() {}
virtual QImage apply(const QImage & image) = 0;
};
#endif // FILTER_H
#ifndef HISTOGRAM_H
#define HISTOGRAM_H
#include <vector>
#include <QString>
#include <QImage>
class Histogram {
public:
Histogram(const QImage & image, int channel);
virtual ~Histogram() {}
std::vector<int> get_data() const {return this->data;}
QString toString() const;
Histogram equalize() const;
static QImage equalize_image(const QImage & image);
static std::vector<Histogram> create_all(const QImage & image);
private:
typedef int (*channel_map_function)(QRgb);
Histogram(int channel, int size, const std::vector<int> & data);
static channel_map_function CHANNEL_MAP[4];
void create(const QImage & image);
int channel;
unsigned int size;
std::vector<int> data;
};
#endif // HISTOGRAM_H
#ifndef IMAGEDISPLAY_H
#define IMAGEDISPLAY_H
#include <QGLWidget>
class QWheelEvent;
class ImageDisplay : public QGLWidget {
public:
ImageDisplay(QWidget * parent = 0);
virtual ~ImageDisplay();
void set_image(const QImage & image);
void set_zoom(float zoom) {m_zoom = zoom;}
float zoom() const {return m_zoom;}
protected:
virtual void wheelEvent(QWheelEvent * e);
private:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
GLuint texture;
QSize image_size;
float m_zoom;
};
#endif // IMAGEDISPLAY_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <string>
#include <vector>
#include <QMainWindow>
#include "include/chartview.h"
class ImageDisplay;
class QPushButton;
class SettingsDialog;
class WeightDialog;
class Filter;
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget * parent = nullptr);
virtual ~MainWindow();
public slots:
void open_image_dialog();
void open_last();
void revert_image();
void close_image();
void equalize_image();
void mean_filter();
void weighted_filter();
void reset_zoom();
void show_image();
void show_histogram();
void show_settings_dialog();
private:
void init();
void open_image(const QImage & image);
void load_image(QImage * image);
void release_images();
void apply_filter(Filter * filter);
static const ChartView::Mode CHART_DEFAULT_MODE
= ChartView::Mode::LINE;
std::string last_path;
QWidget * displayed;
ImageDisplay * image_display;
QImage * original_image;
QImage * displayed_image;
QWidget * histograms_view;
SettingsDialog * settings_dialog;
WeightDialog * weight_dialog;
std::vector<ChartView *> histograms;
QPushButton * image_button;
QPushButton * histogram_button;
};
#endif // MAINWINDOW_H
#ifndef MEAN_FILTER_H
#define MEAN_FILTER_H
#include "include/weightedfilter.h"
class MeanFilter : public WeightedFilter {
public:
MeanFilter(int size)
: WeightedFilter(
std::vector<std::vector<float>>(
size, std::vector<float>(size, 1.0f))) {}
};
#endif // MEAN_FILTER_H
#ifndef SETTINGS_DIALOG_H
#define SETTINGS_DIALOG_H
#include <QDialog>
#include "include/chartview.h"
class QGroupBox;
class QPushButton;
class QRadioButton;
class SettingsDialog : public QDialog {
Q_OBJECT
public:
SettingsDialog(
QWidget * parent = nullptr,
ChartView::Mode mode = ChartView::Mode::LINE);
ChartView::Mode mode() const {return this->m_mode;}
private slots:
void ok_button_clicked();
private:
void init();
QGroupBox * chart_mode_group;
QRadioButton * chart_line_radio;
QRadioButton * chart_bars_radio;
QPushButton * ok_button;
QPushButton * cancel_button;
ChartView::Mode m_mode;
};
#endif // SETTINGS_DIALOG_H
#ifndef WEIGHT_DIALOG_H
#define WEIGHT_DIALOG_H
#include <vector>
#include <QDialog>
class QGridLayout;
class QPushButton;
class WeightDialog : public QDialog {
Q_OBJECT
public:
WeightDialog(QWidget * parent = 0);
std::vector<std::vector<float>> weights() const {return m_weights;}
private slots:
void number_text_changed(const QString & text);
void ok_button_clicked();
private:
void init();
void update_size();
std::vector<std::vector<float>> generate_weights();
unsigned int m_size;
std::vector<std::vector<float>> m_weights;
QGridLayout * grid_layout;
QPushButton * ok_button;
QPushButton * cancel_button;
};
#endif // WEIGHT_DIALOG_H
#ifndef WEIGHTED_FILTER_H
#define WEIGHTED_FILTER_H
#include "include/filter.h"
#include <vector>
class WeightedFilter : public Filter {
public:
WeightedFilter(const std::vector<std::vector<float>> & weights);
virtual QImage apply(const QImage & image);
protected:
float calculate_sum(const std::vector<std::vector<float>> & v) const;
static std::vector<std::vector<float>> copy_weights(
const std::vector<std::vector<float>> & weights);
QRgb round_neighbors(
unsigned int x, unsigned int y, const QImage & image) const;
unsigned int round_value(float v) const;
unsigned int size;
float sum;
std::vector<std::vector<float>> weights;
};
#endif // WEIGHTED_FILTER_H
#include "include/chartview.h"
#include <algorithm>
ChartView::ChartView(QWidget * parent)
: QGLWidget(parent), mode(Mode::LINE) {
}
void ChartView::set_data(const std::vector<int> & data) {
this->data = data;
this->max = *std::max_element(
this->data.cbegin(), this->data.cend(),
[](int x, int y){return abs(x) < abs(y);});
}
/*virtual*/
void ChartView::initializeGL() {
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
/*virtual*/
void ChartView::resizeGL(int w, int h) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
glOrtho(-0.5, 0.5, -0.5, 0.5, 0.1, 1000.0);
}
/*virtual*/
void ChartView::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-0.5f, -0.5f, -1.5f);
glScalef(1.0f / this->data.size(), 1.0f / this->max, 1.0f);
if(this->mode == Mode::BARS)
this->draw_bars();
else if(this->mode == Mode::LINE)
this->draw_line();
}
void ChartView::draw_bars() {
for(unsigned int i = 0; i < this->data.size(); i++) {
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
glVertex2i(i, 0);
glVertex2i(i + 1, 0);
glVertex2i(i + 1, this->data[i]);
glVertex2i(i, this->data[i]);
glEnd();
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINE_LOOP);
glVertex2i(i, 0);
glVertex2i(i + 1, 0);
glVertex2i(i + 1, this->data[i]);
glVertex2i(i, this->data[i]);
glEnd();
}
}
void ChartView::draw_line() {
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_LINE_STRIP);
for(unsigned int i = 0; i < this->data.size(); i++)
glVertex2i(i, this->data[i]);
glEnd();
}
#include "include/histogram.h"
#include <QImage>
/*static*/
Histogram::channel_map_function Histogram::CHANNEL_MAP[4] =
{qRed, qGreen, qBlue, qAlpha};
Histogram::Histogram(const QImage & image, int channel)
: channel(channel), size(image.width() * image.height()), data(256, 0) {
this->create(image);
}
Histogram::Histogram(int channel, int size, const std::vector<int> & data)
: channel(channel), size(size), data(data) {}
/*static*/
std::vector<Histogram> Histogram::create_all(const QImage & image) {
int channels =
image.isGrayscale() ? 1 :
image.hasAlphaChannel() ? 4 :
3;
std::vector<Histogram> histograms;
histograms.reserve(channels);
for(int i = 0; i < channels; ++i)
histograms.push_back(Histogram(image, i));
return histograms;
}
void Histogram::create(const QImage & image) {
for(int y = 0; y < image.height(); y++)
for(int x = 0; x < image.width(); x++)
++this->data[CHANNEL_MAP[channel](image.pixel(x, y))];
}
QString Histogram::toString() const {
QString s;
for(unsigned int iRgb = 0; iRgb < 256; ++iRgb)
s += QString("%1: %2\n").arg(
QString::number(iRgb),
QString(
static_cast<unsigned int>(
static_cast<float>(data[iRgb]) / size * 100.0f),
'o'));
return s;
}
Histogram Histogram::equalize() const {
float freq[256];
for(unsigned int i = 0; i < 256; i++)
freq[i] = static_cast<float>(data[i]) / static_cast<float>(size);
std::vector<int> new_data(256);
float sum = 0;
for(unsigned int i = 0; i < 256; i++)
new_data[i] = (sum += freq[i]) * 255;
return Histogram(this->channel, this->size, new_data);
}
/*static*/
QImage Histogram::equalize_image(const QImage & image) {
std::vector<Histogram> histograms = Histogram::create_all(image);
std::vector<std::vector<int>> equalized(histograms.size());
for(unsigned int i = 0; i < histograms.size(); ++i)
equalized[i] = histograms[i].equalize().get_data();
QImage copy = QImage(image);
bool is_gray = image.isGrayscale();
bool has_alpha = image.hasAlphaChannel();
for(int y = 0; y < image.height(); y++) {
for(int x = 0; x < image.width(); x++) {
QRgb pixel = image.pixel(x, y);
copy.setPixel(
x, y, qRgba(
equalized[is_gray ? 0 : 0][qRed(pixel)],
equalized[is_gray ? 0 : 1][qGreen(pixel)],
equalized[is_gray ? 0 : 2][qBlue(pixel)],
equalized[has_alpha ? 3 : 0][qAlpha(pixel)]));
}
}
return copy;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment