Skip to content

Instantly share code, notes, and snippets.

@elliotwoods
Created February 16, 2018 12:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elliotwoods/ea9535667d346061b416c4f302f22628 to your computer and use it in GitHub Desktop.
Save elliotwoods/ea9535667d346061b416c4f302f22628 to your computer and use it in GitHub Desktop.
Comparison of subpixel routines
#include "pch.h"
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
this->gui.init();
}
//--------------------------------------------------------------
void ofApp::init() {
try {
auto directory = ofDirectory(".");
directory.listDir();
ofxRulr::Utils::ScopedProcess scopedProcess("Loading images", true, directory.size());
for (const auto & file : directory) {
ofxRulr::Utils::ScopedProcess scopedProcess("Loading " + file.getFileName(), false);
auto extension = ofToLower(file.getExtension());
if (extension != "jpg") {
cout << file.path();
continue;
}
auto cameraImage = make_unique<CameraImage>();
cameraImage->filename = file.getFileName();
cameraImage->image.load(file);
if (cameraImage->image.getPixels().getNumChannels() != 1) {
//we're jpg so this is actually always true
cv::cvtColor(ofxCv::toCv(cameraImage->image.getPixels())
, cameraImage->grayscale
, CV_RGB2GRAY);
}
else {
cameraImage->grayscale = ofxCv::toCv(cameraImage->image.getPixels());
}
if (!this->cameraImages.empty()) {
const auto & firstImage = this->cameraImages.front();
if (cameraImage->image.getWidth() != firstImage->image.getWidth()
|| cameraImage->image.getHeight() != firstImage->image.getHeight()) {
throw(ofxRulr::Exception("Image size mismatch"));
}
}
{
//build panel
cameraImage->panel = this->gui.add(cameraImage->image, cameraImage->filename);
auto & imageRef = *cameraImage;
cameraImage->panel->onDrawImage += [&imageRef](ofxCvGui::DrawImageArguments & args) {
for (const auto & marker : imageRef.markers) {
ofPolyline line;
line.addVertex(ofxCv::toOf(marker[0]));
line.addVertex(ofxCv::toOf(marker[1]));
line.addVertex(ofxCv::toOf(marker[2]));
line.addVertex(ofxCv::toOf(marker[3]));
line.addVertex(ofxCv::toOf(marker[0]));
ofPushStyle();
{
ofSetColor(0);
ofSetLineWidth(3.0f);
line.draw();
ofSetColor(255, 0, 0);
ofSetLineWidth(1.0f);
line.draw();
}
ofPopStyle();
}
};
}
this->cameraImages.emplace_back(move(cameraImage));
}
if (this->cameraImages.empty()) {
throw(ofxRulr::Exception("No images found. Please add evaluation images to the data folder."));
}
scopedProcess.end();
}
RULR_CATCH_ALL_TO_ALERT;
try {
ofxRulr::Utils::ScopedProcess scopedProcess("Finding markers", true, this->cameraImages.size());
aruco::MarkerDetector markerDetector;
markerDetector.setDetectionMode(aruco::DetectionMode::DM_NORMAL);
markerDetector.setDictionary(aruco::Dictionary::ARUCO_MIP_36h12);
for (const auto & cameraImage : this->cameraImages) {
ofxRulr::Utils::ScopedProcess scopedProcess("Analyzing " + cameraImage->filename, false);
//just in case aruco does anything at all with the RGB info
markerDetector.detect(ofxCv::toCv(cameraImage->image.getPixels()), cameraImage->markers);
for (auto & marker : cameraImage->markers) {
//perform sub-pixel detection if we're on our winged marker
if (marker.id == WINGED_MARKER_ID) {
int windowSize = (ofxCv::toOf(marker[1]) - ofxCv::toOf(marker[0])).length() / 16;
cv::TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER
, 30
, 0.001);
cv::cornerSubPix(cameraImage->grayscale
, (vector<cv::Point2f> &)marker
, cv::Size(windowSize, windowSize)
, cv::Size(2, 2)
, criteria);
}
//record image points
cameraImage->markerImagePoints.emplace(marker.id, marker);
}
}
scopedProcess.end();
}
RULR_CATCH_ALL_TO_ALERT;
try {
//calculate deviations
{
//set blank values
this->cornerResults.emplace(0, vector<CornerResult>(4));
this->cornerResults.emplace(1, vector<CornerResult>(4));
}
//accumulate data
for (const auto & cameraImage : this->cameraImages) {
for (const auto & marker : cameraImage->markers) {
for (int i = 0; i < 4; i++) {
this->cornerResults[marker.id][i].positions.push_back(marker[i]);
}
}
}
//calculate
for (auto & markerCornerResult : this->cornerResults) {
for (auto & cornerResult : markerCornerResult.second) {
https://stackoverflow.com/questions/11567307/calculate-mean-for-vector-of-points
cv::Mat mean_;
cv::reduce(cornerResult.positions, mean_, 1, CV_REDUCE_AVG);
cornerResult.mean.x = mean_.at<float>(0, 0);
cornerResult.mean.y = mean_.at<float>(0, 1);
float deviation = 0.0f;
for (const auto & position : cornerResult.positions) {
deviation += (ofxCv::toOf(position) - ofxCv::toOf(cornerResult.mean)).lengthSquared();
}
deviation /= cornerResult.positions.size();
deviation = sqrt(deviation);
cornerResult.deviation = deviation;
}
}
}
RULR_CATCH_ALL_TO_ALERT;
try {
//add the summary panel
cv::Mat average;
{
const auto & firstImage = this->cameraImages.front()->image;
cv::Mat accumulate = cv::Mat::zeros(cv::Size(firstImage.getWidth(), firstImage.getHeight()), CV_32F);
for (const auto & cameraImage : this->cameraImages) {
cv::add(accumulate
, cameraImage->grayscale
, accumulate
, cv::Mat()
, CV_32F);
}
accumulate /= (float) this->cameraImages.size();
accumulate.convertTo(average, CV_8U);
}
ofxCv::copy(average, this->previewAverage.getPixels());
this->previewAverage.update();
auto panel = this->gui.add(this->previewAverage, "Summary");
panel->onDrawImage += [this](ofxCvGui::DrawImageArguments &) {
ofPushStyle();
{
ofSetColor(255, 0, 0);
for (const auto & cornerResultMarker : this->cornerResults) {
for (const auto & cornerResult : cornerResultMarker.second) {
for (const auto & position : cornerResult.positions) {
ofPushMatrix();
{
//draw a cross
ofTranslate(ofxCv::toOf(position));
ofDrawLine(-5, 0, 5, 0);
ofDrawLine(0, -5, 0, 5);
}
ofPopMatrix();
}
ofDrawBitmapString("Deviation : " + ofToString(cornerResult.deviation), ofxCv::toOf(cornerResult.mean));
}
}
}
ofPopStyle();
};
}
RULR_CATCH_ALL_TO_ALERT;
}
//--------------------------------------------------------------
void ofApp::update(){
if (ofGetFrameNum() == 1) {
this->init();
}
}
//--------------------------------------------------------------
void ofApp::draw(){
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}
#pragma once
#include "ofMain.h"
#include "ofxCvGui.h"
#include "ofxCvMin.h"
#include "ofxRulr.h"
#define WINGED_MARKER_ID 1
struct CameraImage {
string filename;
ofImage image;
cv::Mat grayscale;
shared_ptr<ofxCvGui::Panels::Image> panel;
vector<aruco::Marker> markers;
map<size_t, vector<cv::Point2f>> markerImagePoints;
};
struct CornerResult {
cv::Point2f mean;
float deviation;
vector<cv::Point2f> positions;
};
class ofApp : public ofBaseApp{
public:
void setup();
void init();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ofxCvGui::Builder gui;
vector<unique_ptr<CameraImage>> cameraImages;
ofImage previewAverage;
map<int, vector<CornerResult>> cornerResults;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment