Commit a606c4d7 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Merge branch 'development/clean-legacy-maxtree' into development/maxtrees

parents 0fa63169 dfca5836
Pipeline #16017 passed with stages
in 20 minutes and 24 seconds
override CXXFLAGS += -I ../.. -std=c++11 -W -Wall
LDLIBS=-lfreeimage -lboost_program_options -ltbb
#include <mln/accu/accumulators/sum.hpp>
#include <mln/core/algorithm/accumulate.hpp>
#include <mln/core/algorithm/copy.hpp>
#include <mln/core/algorithm/transform.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <boost/program_options.hpp>
#include <mln/core/image/morphers/casted_image.hpp>
#include <mln/core/win2d.hpp>
#include <mln/morpho/structural/opening.hpp>
namespace mln
{
static const rect2d qcmbox = make_rectangle2d(15, 41);
static constexpr float qcmboxvdist = 50.2;
static constexpr int qcmboxhdist = 60;
static constexpr int qcmcolhdist = 481;
static constexpr point2d pref = {168, 2389};
static constexpr char REPA = 0x01;
static constexpr char REPB = 0x02;
static constexpr char REPC = 0x04;
static constexpr char REPD = 0x08;
static constexpr char REPE = 0x10;
static constexpr char REPALL = 0x1F;
static unsigned detection_threshold = 200;
image2d<rgb8> imdebug;
image2d<bool> transpose(const image2d<bool>& x)
{
box2d b1 = x.domain();
box2d b2 = {{b1.pmin[1], b1.pmin[0]}, {b1.pmax[1], b1.pmax[0]}};
image2d<bool> out(b2);
mln_foreach (auto pxin, x.pixels())
{
point2d p = pxin.point();
out.at(p[1], p[0]) = pxin.val();
}
return out;
}
point2d detect_offset(const image2d<uint8>& f)
{
mln_entering("Offset detection");
// rect2d se = make_rectangle2d(21, 51);
box2d dom = {{125, 2300}, {250, 2470}};
image2d<bool> bin(dom);
copy((f < 180) | dom, bin);
// auto markers = morpho::opening(f, se);
rect2d se = make_rectangle2d(21,49);
bin = morpho::structural::opening(bin, se);
// auto sub = bin | dom;
mln_foreach (auto px, bin.pixels())
if (px.val())
{
mln_exiting();
return px.point();
}
std::cerr << "Marker not found" << std::endl;
std::exit(1);
}
template <class I>
bool is_plain(const I& f, point2d p)
{
int count = accumulate(f | qcmbox(p), accu::features::sum<>());
if (count > detection_threshold)
{
for (int i = p[1] - 20; i <= (p[1] + 20); ++i)
{
imdebug.at(p[0] - 8, i) = rgb8{255, 0, 0};
imdebug.at(p[0] - 7, i) = rgb8{255, 0, 0};
imdebug.at(p[0] + 7, i) = rgb8{255, 0, 0};
imdebug.at(p[0] + 8, i) = rgb8{255, 0, 0};
}
}
// std::cout << p << ":" << count << std::endl;
return count > detection_threshold;
}
template <class I>
char detect_question(const I& bin, point2d pos)
{
char response1 = 0;
char response2 = 0;
point2d p = pos;
for (int i = 0; i < 5; ++i, p[1] += qcmboxhdist)
if (is_plain(bin, p))
response1 |= (1 << i);
p = pos;
p[0] += qcmboxvdist;
for (int i = 0; i < 5; ++i, p[1] += qcmboxhdist)
if (is_plain(bin, p))
response2 |= (1 << i);
if (response2 == REPALL)
return 0;
else if (response2)
return response2;
else if (response1 and response1 != REPALL)
return response1;
else
return 0;
}
void detect_all(const image2d<uint8>& f, point2d offset = {0, 0})
{
mln_entering("Detection des cases");
auto bin = f < 200;
rect2d se = make_rectangle2d(15, 40);
// Login
{
point2d plogin = point2d{228, 1895} + offset;
point2df p = plogin;
for (int j = 0; j < 6; ++j, p[1] += qcmboxhdist)
{
p[0] = plogin[0];
for (int i = 0; i < 26; ++i, p[0] += qcmboxvdist)
{
if (is_plain(bin, p))
{
std::cout << (char)('a' + i);
break;
}
}
}
std::cout << "-";
p[1] += qcmboxhdist;
p[0] = plogin[0];
for (int i = 0; i < 26; ++i, p[0] += qcmboxvdist)
{
if (is_plain(bin, p))
{
std::cout << (char)('a' + i);
break;
}
}
std::cout << std::endl;
}
// Les questions
{
point2d p0 = point2d{1734, 156} + offset;
point2df p = p0;
for (int j = 0; j < 5; ++j, p[1] += qcmcolhdist)
{
p[0] = p0[0];
for (int i = 0; i < 10; ++i, p[0] += 2 * qcmboxvdist)
{
char res = detect_question(bin, p);
// std::cout << (j*10 + i + 1) << " ";
for (int k = 0; k < 5; ++k)
if (res & (1 << k))
std::cout << (char)('a' + k);
std::cout << std::endl;
}
}
}
mln_exiting();
}
}
int main(int argc, char** argv)
{
using namespace mln;
namespace po = boost::program_options;
po::options_description desc("Allowed options");
desc.add_options()("help", "produce help message")(
"threshold,t", po::value<unsigned>(&detection_threshold)->default_value(200), "Set threshold detection");
po::options_description desc2("");
desc2.add_options()("input", po::value<std::string>()->required(),
"input image")("output", po::value<std::string>()->required(), "output image");
po::positional_options_description pd;
pd.add("input", 1);
pd.add("output", 1);
desc2.add(desc);
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(desc2).positional(pd).run(), vm);
try
{
po::notify(vm);
}
catch (...)
{
std::cout << "Usage: " << argv[0]
<< " input output\n"
"Les images doivent être en 200dpi\n"
<< desc << "\n";
return 1;
}
if (vm.count("help"))
{
std::cout << desc << "\n";
return 1;
}
image2d<uint8> f;
{
mln_entering("Conversion B&W") image2d<rgb8> ima;
io::imread(vm["input"].as<std::string>(), ima);
f = transform(ima, [](const rgb8& v) -> uint8 { return sum(v) / 3; });
imdebug = ima;
copy(f, imdebug);
mln_exiting();
}
point2d ref = detect_offset(f);
point2d offset = ref - pref;
detect_all(f, offset);
io::imsave(imdebug, vm["output"].as<std::string>());
// std::cout << "Ref: " << ref << std::endl;
// std::cout << "Offset: " << offset << std::endl;
}
#!/usr/bin/python
#coding: utf-8
import sys
import matplotlib.pyplot as plt
import math
#Usage: ./qcm.py input.txt input.tiff output.tiff
assert(len(sys.argv) > 3)
# Import note
# f = open(sys.argv[1])
# Rrep = [ line.strip() for line in f ]
# f.close()
Rrep = [ "bc", "c", "d", "a", "b", "d", "b", "c", "abd", "abc",
"bd", "abd", "b", "a", "b" ]
# Import student
f = open(sys.argv[1])
login = f.readline().strip()
Srep = [ line.strip() for line in f ]
f.close()
#print Srep, len(Rrep)
# Get the note
notes = [ 1 if u == v else 0 if v == "" else -.25 for u,v in zip(Rrep, Srep) ]
# Print
note = 20.0 * sum(notes) / len(notes)
note = math.ceil(note * 2) / 2 # arrondi à 0.5
print "%s,%.01f,%s" % (login, note, sys.argv[2])
###############################
## Write the image ###
###############################
img = plt.imread(sys.argv[2])
ypixels, xpixels, _ = img.shape
dpi = 200.
xinch = xpixels / dpi
yinch = ypixels / dpi
fig = plt.figure(figsize=(xinch,yinch))
ax = plt.axes([0., 0., 1., 1.], frameon=False, xticks=[],yticks=[])
ax.imshow(img)
x = 450
y = 1750
for k,n in enumerate(notes):
i = k / 10
j = k % 10
plt.text(x + 481 * i, 1750 + j * 100, str(n), color="red")
plt.text(180,1000, login + " : " + str(note), color="red", fontsize=15)
plt.draw()
plt.savefig(sys.argv[3], dpi=dpi)
#pragma once
#include <mln/core/assert.hpp>
#include <array>
#include <memory>
#include <numeric>
#include <vector>
namespace mln
{
template <typename T, std::size_t nLevel, typename Allocator = std::allocator<T>, bool queue = false,
typename Enable = void>
struct bounded_hqueue
{
bounded_hqueue();
explicit bounded_hqueue(const size_t* histo);
~bounded_hqueue();
void init(const size_t* histo);
bool empty(unsigned l) const;
void push_at_level(const T& x, unsigned l);
T top_at_level(unsigned l) const;
T pop_at_level(unsigned l);
private:
std::array<T*, nLevel> m_head;
std::array<T*, nLevel> m_tail;
Allocator m_allocator;
T* m_q;
T* m_end;
};
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
struct bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>
{
bounded_hqueue();
explicit bounded_hqueue(const size_t* histo);
~bounded_hqueue();
void init(const size_t* histo);
bool empty(unsigned l) const;
void push_at_level(const T& x, unsigned l);
T top_at_level(unsigned l) const;
T pop_at_level(unsigned l);
private:
std::vector<T*> m_head;
std::vector<T*> m_tail;
Allocator m_allocator;
T* m_q;
T* m_end;
};
/********************/
/** Implementation **/
/********************/
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline bounded_hqueue<T, nLevel, Allocator, queue, Enable>::bounded_hqueue()
: m_head{{
NULL,
}}
, m_tail{{
NULL,
}}
, m_q(NULL)
, m_end(NULL)
{
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline bounded_hqueue<T, nLevel, Allocator, queue, Enable>::bounded_hqueue(const size_t* histo)
{
init(histo);
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline bounded_hqueue<T, nLevel, Allocator, queue, Enable>::~bounded_hqueue()
{
if (m_q != NULL)
{
for (unsigned i = 0; i < nLevel; ++i)
for (T* ptr = m_head[i]; ptr != m_tail[i]; ++ptr)
m_allocator.destroy(ptr);
m_allocator.deallocate(m_q, m_end - m_q);
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline void bounded_hqueue<T, nLevel, Allocator, queue, Enable>::init(const size_t* histo)
{
mln_precondition(m_q == NULL);
unsigned nelements = std::accumulate(histo, histo + nLevel, 0u);
m_q = m_allocator.allocate(nelements);
m_end = m_q + nelements;
unsigned n = 0;
for (unsigned i = 0; i < nLevel; ++i)
{
m_head[i] = m_tail[i] = m_q + n;
n += histo[i];
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline bool bounded_hqueue<T, nLevel, Allocator, queue, Enable>::empty(unsigned level) const
{
mln_precondition(level < nLevel);
return m_head[level] == m_tail[level];
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline void bounded_hqueue<T, nLevel, Allocator, queue, Enable>::push_at_level(const T& x, unsigned level)
{
mln_precondition(level < nLevel);
mln_precondition(m_tail[level] < m_end and (level == nLevel - 1 or m_tail[level] < m_head[level + 1]));
m_allocator.construct(m_tail[level]++, x);
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline T bounded_hqueue<T, nLevel, Allocator, queue, Enable>::pop_at_level(unsigned level)
{
mln_precondition(level < nLevel);
mln_precondition(!empty(level));
if (queue)
{
T x = std::move(*(m_head[level]));
m_allocator.destroy(m_head[level]++);
return x;
}
else
{
T x = std::move(*(--m_tail[level]));
m_allocator.destroy(m_tail[level]);
return x;
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue, typename Enable>
inline T bounded_hqueue<T, nLevel, Allocator, queue, Enable>::top_at_level(unsigned level) const
{
mln_precondition(level < nLevel);
mln_precondition(!empty(level));
if (queue)
{
T x = *(m_head[level]);
return x;
}
else
{
T x = *(m_tail[level] - 1);
return x;
}
}
/*********************************/
/* Implementation specialization */
/*********************************/
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::bounded_hqueue()
: m_q(NULL)
, m_end(NULL)
{
m_head.resize(nLevel);
m_tail.resize(nLevel);
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::bounded_hqueue(
const size_t* histo)
{
init(histo);
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::~bounded_hqueue()
{
if (m_q != NULL)
{
for (std::size_t i = 0; i < nLevel; ++i)
for (T* ptr = m_head[i]; ptr != m_tail[i]; ++ptr)
m_allocator.destroy(ptr);
m_allocator.deallocate(m_q, m_end - m_q);
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline void bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::init(
const size_t* histo)
{
mln_precondition(m_q == NULL);
size_t nelements = std::accumulate(histo, histo + nLevel, size_t(0));
m_q = m_allocator.allocate(nelements);
m_end = m_q + nelements;
unsigned n = 0;
for (std::size_t i = 0; i < nLevel; ++i)
{
m_head[i] = m_tail[i] = m_q + n;
n += static_cast<unsigned>(histo[i]);
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline bool bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::empty(
unsigned level) const
{
mln_precondition(level < nLevel);
return m_head[level] == m_tail[level];
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline void bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::push_at_level(
const T& x, unsigned level)
{
mln_precondition(level < nLevel);
mln_precondition(m_tail[level] < m_end and (level == nLevel - 1 or m_tail[level] < m_head[level + 1]));
m_allocator.construct(m_tail[level]++, x);
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline T bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::pop_at_level(
unsigned level)
{
mln_precondition(level < nLevel);
mln_precondition(!empty(level));
if (queue)
{
T x = std::move(*(m_head[level]));
m_allocator.destroy(m_head[level]++);
return x;
}
else
{
T x = std::move(*(--m_tail[level]));
m_allocator.destroy(m_tail[level]);
return x;
}
}
template <typename T, std::size_t nLevel, typename Allocator, bool queue>
inline T bounded_hqueue<T, nLevel, Allocator, queue, std::enable_if_t<(nLevel > 16)>>::top_at_level(
unsigned level) const
{
mln_precondition(level < nLevel);
mln_precondition(!empty(level));
if (queue)
{
T x = *(m_head[level]);
return x;
}
else
{
T x = *(m_tail[level] - 1);
return x;
}
}
} // namespace mln
#pragma once
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/morpho/component_tree/component_tree.hpp>
#include <iosfwd>
namespace mln
{
namespace morpho
{