Last active
January 4, 2016 19:19
-
-
Save denkiwakame/8667025 to your computer and use it in GitHub Desktop.
グレイコードデコーダ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <highgui.h> | |
#include <cv.h> | |
#include <cxcore.h> | |
#include <assert.h> | |
#include <iostream> | |
#include <sstream> | |
#include <math.h> | |
#include "fileio_util.hpp" | |
class GrayCodeDecoder { | |
public: | |
// constructor | |
GrayCodeDecoder(int _graycode_partition_num_x, int _graycode_partitoin_num_y); | |
~GrayCodeDecoder(); | |
void endecode(const std::string& dirpath, const std::string& file_ext, int first_idx); | |
// getter for data | |
cv::Mat getDecodedDataX() const; | |
cv::Mat getDecodedDataY() const; | |
cv::Mat getMaskImg() const; | |
std::string toBinaryString(int num) const; | |
// confirms result | |
void showDecodedResult() const; | |
// utils | |
void showImg(const cv::Mat& img, const int waiting_time) const; | |
private: | |
// called in void endecode() | |
void setMaskImg(const cv::Mat& img1, const cv::Mat& img2); | |
void setMaskContour(const cv::Mat& img); | |
void encodeImgX(const cv::Mat& img); | |
void encodeImgY(const cv::Mat& img); | |
// called in encodeImg(X|Y) | |
void _encodeImg(const cv::Mat& img, cv::Mat& decoded_data); | |
const int graycode_partition_num_x; | |
const int graycode_partition_num_y; | |
int img_cols; | |
int img_rows; | |
// background: I(x,y) = 0 projected area: I(x,y) = 255 | |
cv::Mat mask_img; | |
std::vector< cv::Point > masked_points; | |
cv::Mat decoded_dataX; | |
cv::Mat decoded_dataY; | |
}; | |
GrayCodeDecoder::GrayCodeDecoder(int _graycode_partition_num_x, int _graycode_partition_num_y) | |
: graycode_partition_num_x(_graycode_partition_num_x), | |
graycode_partition_num_y(_graycode_partition_num_y) | |
{ | |
}; | |
GrayCodeDecoder::~GrayCodeDecoder(){}; | |
void GrayCodeDecoder::showImg(const cv::Mat& img, const int waiting_time) const | |
{ | |
cv::imshow("window", img); | |
cv::waitKey(waiting_time); | |
} | |
void GrayCodeDecoder::endecode(const std::string& dirpath, const std::string& file_ext, int first_idx) { | |
// TODO | |
// detects projected area | |
cv::Mat base_img1 = cv::imread(fileio::create_filepath(0, dirpath, file_ext), 1); | |
assert(!base_img1.empty() && "cannot load base img"); | |
//cv::Mat base_img2 = cv::imread(fileio::create_filepath(1, dirpath, file_ext), 1); | |
// this->setMaskImg(base_img1, base_img2); | |
this->setMaskContour(base_img1); | |
assert(!this->mask_img.empty() && "mask img hasn't yet been set"); | |
// set input img size | |
this->img_cols = base_img1.cols; | |
this->img_rows = base_img1.rows; | |
base_img1.release(); | |
//base_img2.release(); | |
this->decoded_dataX = cv::Mat(this->img_rows, this->img_cols, CV_16UC1, cv::Scalar(0)); | |
this->decoded_dataY = cv::Mat(this->img_rows, this->img_cols, CV_16UC1, cv::Scalar(0)); | |
int ximg_idx_first = first_idx; | |
int ximg_idx_last = this->graycode_partition_num_x + ximg_idx_first - 1; | |
int yimg_idx_first = ximg_idx_last + 1; | |
int yimg_idx_last = this->graycode_partition_num_y + yimg_idx_first - 1; | |
for (int i=ximg_idx_first; i<= ximg_idx_last; i++){ | |
cv::Mat img = cv::imread(fileio::create_filepath(i, dirpath, file_ext), 0); | |
assert(!img.empty() && "cannot load img"); | |
this->showImg(img, 0); | |
this->encodeImgX(img); | |
} | |
for (int i=yimg_idx_first; i<= yimg_idx_last; i++){ | |
cv::Mat img = cv::imread(fileio::create_filepath(i, dirpath, file_ext), 0); | |
assert(!img.empty() && "cannot load img"); | |
this->showImg(img, 0); | |
this->encodeImgY(img); | |
} | |
cv::destroyAllWindows(); | |
} | |
// TODO 手でやったほうがいい | |
void GrayCodeDecoder::setMaskImg(const cv::Mat& img1, const cv::Mat& img2) | |
{ | |
assert((img1.channels()==3 && img2.channels()==3) && "input img should be grayscale"); | |
cv::Mat diff_img; | |
cv::absdiff(img1, img2, diff_img); | |
cv::Mat diff_img_gray; | |
cv::cvtColor(diff_img, diff_img_gray, CV_RGB2GRAY); | |
diff_img.release(); | |
for (int rows=0; rows < diff_img_gray.rows; rows++){ | |
for (int cols=0; cols < diff_img_gray.cols; cols++){ | |
diff_img_gray.at<unsigned char>(rows,cols) = diff_img_gray.at<unsigned char>(rows,cols) > 30 ? 255 : 0; | |
} | |
} | |
this->mask_img = diff_img_gray; | |
this->showImg(diff_img_gray, 0); | |
}; | |
void GrayCodeDecoder::encodeImgX(const cv::Mat& img) { | |
this->_encodeImg(img, this->decoded_dataX); | |
} | |
void GrayCodeDecoder::encodeImgY(const cv::Mat& img) { | |
this->_encodeImg(img, this->decoded_dataY); | |
} | |
// TODO thresh | |
void GrayCodeDecoder::_encodeImg(const cv::Mat& img, cv::Mat& decoded_data) { | |
/********************************************** | |
* mask_img: projected pattern area 1 else 0 | |
* img: picture | |
* decoded_data: graycode img 001000.... | |
* ********************************************/ | |
unsigned char thresh = 125; | |
cv::Mat dst; | |
cv::threshold(img,dst,thresh,255,cv::THRESH_BINARY|cv::THRESH_OTSU); | |
this->showImg(dst,0); | |
dst.release(); | |
assert((img.channels() == this->mask_img.channels()) && "img and mask channel not equal"); | |
for (int cols=0; cols < img.cols; cols++) { | |
for (int rows=0; rows < img.rows; rows++) { | |
// target area | |
if (this->mask_img.at<unsigned char>(rows,cols) == 0) { | |
continue; | |
} | |
int code = img.at<unsigned char>(rows, cols) > thresh ? 1 : 0; | |
decoded_data.at<unsigned short>(rows,cols) = (decoded_data.at<unsigned short>(rows,cols) << 1) + code; | |
} | |
} | |
}; | |
cv::Mat GrayCodeDecoder::getDecodedDataX() const { | |
return this->decoded_dataX; | |
} | |
cv::Mat GrayCodeDecoder::getDecodedDataY() const { | |
return this->decoded_dataY; | |
} | |
cv::Mat GrayCodeDecoder::getMaskImg() const { | |
assert(!this->mask_img.empty() && "mask img empty"); | |
return this->mask_img; | |
} | |
// util | |
std::string GrayCodeDecoder::toBinaryString(int num) const { | |
if (num == 0) return "0"; | |
std::string binary_num = ""; | |
while(num){ | |
// num 000100 1-> (+1)00001 String | |
binary_num = util::numToString(num & 1) + binary_num; | |
num >>= 1; | |
} | |
return binary_num; | |
} | |
// おまけ | |
// mouse event handler for showdecodedresult | |
void _mouseEvtHandler (int evt, int x, int y, int flag, void* _data){ | |
struct Data { int x; int y; bool clicked;}; | |
Data* data = (Data*)_data; | |
switch(evt){ | |
case cv::EVENT_LBUTTONDOWN: | |
data->x = x; | |
data->y = y; | |
data->clicked = true; | |
std::cout << x << ",\t" << y << std::endl; | |
break; | |
default: | |
break; | |
} | |
} | |
void GrayCodeDecoder::showDecodedResult() const { | |
int graycode_rows = pow(2, this->graycode_partition_num_y); | |
int graycode_cols = pow(2, this->graycode_partition_num_x); | |
cv::Mat graycode_campus = cv::Mat(graycode_rows, graycode_cols, CV_8UC1, cv::Scalar(0)); | |
cv::Mat mask_campus = this->mask_img.clone(); | |
cv::imshow("PRESS ESC TO EXIT", mask_campus); | |
struct Data { int x; int y; bool clicked; }; | |
Data data = { 0, 0, false }; | |
cv::setMouseCallback("PRESS ESC TO EXIT", _mouseEvtHandler, &data); | |
while(1){ | |
if(data.clicked){ | |
int pos_x = this->getDecodedDataX().at<unsigned short>(data.y, data.x); | |
int pos_y = this->getDecodedDataY().at<unsigned short>(data.y, data.x); | |
std::cout << pos_x << "\t" << this->toBinaryString(pos_x) << "\t" << std::endl; | |
std::cout << pos_y << "\t" << this->toBinaryString(pos_y) << "\t" << std::endl; | |
// draw | |
cv::circle(mask_campus, cv::Point(data.x, data.y), 2, cv::Scalar(0), -1); | |
cv::circle(mask_campus, cv::Point(data.x, data.y), 8, cv::Scalar(0)); | |
cv::circle(graycode_campus, cv::Point(pos_x, pos_y), 2, cv::Scalar(255), -1); | |
cv::circle(graycode_campus, cv::Point(pos_x, pos_y), 8, cv::Scalar(255)); | |
cv::imshow("GRAYCODE_PATTERN", graycode_campus); | |
cv::imshow("PRESS ESC TO EXIT", mask_campus); | |
data.clicked = false; | |
} | |
int key = cv::waitKey(10); | |
if (key==27) break; | |
} | |
cv::destroyAllWindows(); | |
} | |
void _mouseEvtHandlerForSetMaskContour (int evt, int x, int y, int flags, void* _data){ | |
struct Data { | |
int vertex_num; | |
std::vector< cv::Point > contour; | |
}; | |
Data* data = (Data*)_data; | |
switch(evt){ | |
case cv::EVENT_LBUTTONDOWN: | |
data->contour.push_back(cv::Point(x,y)); | |
data->vertex_num += 1; | |
break; | |
default: | |
break; | |
} | |
} | |
void GrayCodeDecoder::setMaskContour(const cv::Mat& img) { | |
struct Data { | |
int vertex_num; | |
std::vector< cv::Point > contour; | |
}; | |
Data *data = new Data; | |
data->vertex_num = 0; | |
this->mask_img = cv::Mat(img.rows, img.cols, CV_8UC1, cv::Scalar(0)); | |
assert(mask_img.channels()==1 && "mask img should be grayscale"); | |
cv::imshow("CLICK 4 VERTICES", img); | |
cv::setMouseCallback("CLICK 4 VERTICES", _mouseEvtHandlerForSetMaskContour, data); | |
while(1){ | |
if(data->vertex_num >= 4) { | |
assert(!data->contour.empty() && "contour empty"); | |
std::vector< std::vector< cv::Point > > contours; | |
contours.push_back(data->contour); | |
cv::drawContours(this->mask_img, contours, -1, cv::Scalar(255), -1); | |
cv::imshow("MASK IMG", this->mask_img); | |
cv::waitKey(0); | |
cv::destroyAllWindows(); | |
break; | |
}; | |
int key = cv::waitKey(10); | |
if (key==27) break; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <highgui.h> | |
#include <cv.h> | |
#include <cxcore.h> | |
#include <assert.h> | |
#include <iostream> | |
#include <math.h> | |
// filepath // 000_1~000_10.PNG : blink | |
// 001_1~5 : graycode with exposure | |
class GrayCode { | |
public: | |
GrayCode(int _x_partition_num, int _y_partition_num, const std::string& _window_name); | |
~GrayCode(); | |
void splitX(int depth_limit, int time); | |
void splitY(int depth_limit, int time); | |
bool _split(const cv::Point& tl, const cv::Point& br, const cv::Scalar& cvcolor, int depth, int depth_limit, bool split_x); | |
const cv::Mat getImg() const; | |
void showFilledImg(const cv::Scalar& cvcolor, int time) const; | |
void blink(int times) const; | |
private: | |
const int x_partition_num; | |
const int y_partition_num; | |
const std::string window_name; | |
cv::Mat img; | |
}; | |
GrayCode::GrayCode(int _x_partition_num, int _y_partition_num, const std::string& _window_name) | |
: x_partition_num(_x_partition_num), y_partition_num(_y_partition_num), window_name(_window_name){ | |
int rows = pow(2, this->y_partition_num); | |
int cols = pow(2, this->x_partition_num); | |
this->img = cv::Mat(rows, cols, CV_8UC1, cv::Scalar(0)); | |
assert(img.channels() == 1 && "img channel is not equal to 1"); | |
// WINDOW SETTINGS | |
cv::namedWindow(this->window_name, CV_WINDOW_AUTOSIZE); | |
// TODO 拡大されて危ない | |
// cv::namedWindow(this->window_name, CV_WINDOW_NORMAL); | |
// cv::setWindowProperty(this->window_name, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN); | |
}; | |
GrayCode::~GrayCode(){}; | |
const cv::Mat GrayCode::getImg() const { | |
assert(!this->img.empty() && "img is empty"); | |
return this->img; | |
} | |
void GrayCode::showFilledImg(const cv::Scalar& cvcolor, int time) const { | |
cv::Mat filled_img = cv::Mat(this->img.rows, this->img.cols, CV_8UC1, cvcolor); | |
cv::imshow(this->window_name, filled_img); | |
cv::waitKey(time); | |
filled_img.release(); | |
} | |
void GrayCode::blink(int times) const { | |
for(int i=0; i<times; i++){ | |
this->showFilledImg(cv::Scalar(255), 0); | |
this->showFilledImg(cv::Scalar(0), 0); | |
} | |
} | |
void GrayCode::splitX(int depth_limit, int time){ | |
this->_split(cv::Point(0,0), cv::Point(pow(2,x_partition_num), pow(2,y_partition_num)), cv::Scalar(0), 0, depth_limit, true); | |
cv::imshow(this->window_name, this->img); | |
cv::waitKey(time); | |
}; | |
void GrayCode::splitY(int depth_limit, int time){ | |
this->_split(cv::Point(0,0), cv::Point(pow(2,x_partition_num), pow(2,y_partition_num)), cv::Scalar(0), 0, depth_limit, false); | |
cv::imshow(this->window_name, this->img); | |
cv::waitKey(time); | |
}; | |
bool GrayCode::_split(const cv::Point& tl, const cv::Point& br, const cv::Scalar& cvcolor, int depth, int depth_limit, bool split_x) { | |
if (depth == depth_limit) { | |
cv::rectangle(this->img, cv::Point(tl.x, tl.y), cv::Point(br.x, br.y), cvcolor, -1); | |
return true; | |
}; | |
int mid_x = (tl.x + br.x)/2; | |
int mid_y = (tl.y + br.y)/2; | |
if (split_x){ | |
this->_split(cv::Point(tl.x, tl.y), cv::Point(mid_x, br.y), cv::Scalar(0), depth+1, depth_limit, split_x); | |
this->_split(cv::Point(mid_x+1, tl.y), cv::Point(br.x, br.y), cv::Scalar(255), depth+1, depth_limit, split_x); | |
} else { | |
this->_split(cv::Point(tl.x, tl.y), cv::Point(br.x, mid_y), cv::Scalar(0), depth+1, depth_limit, split_x); | |
this->_split(cv::Point(tl.x, mid_y+1), cv::Point(br.x, br.y), cv::Scalar(255), depth+1, depth_limit, split_x); | |
} | |
return true; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
トリミング