Compare commits
6 Commits
411abd66f6
...
42a019b730
Author | SHA1 | Date |
---|---|---|
The Magician | 42a019b730 | |
The Magician | 1dc003211a | |
The Magician | 974893605d | |
The Magician | 6a7f4171fb | |
The Magician | 6303a2d5e6 | |
The Magician | 908cdface4 |
|
@ -1 +1,3 @@
|
||||||
penny_dreadful_downloader/legality_data/
|
penny_dreadful_downloader/legality_data/
|
||||||
|
MTG-Card-Identifier_v5.pdf
|
||||||
|
info.txt
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
const std::string WINDOW_NAME = "A Scanner Darkly";
|
||||||
|
|
||||||
|
const std::string CANNY_LOWER_THRESHOLD_TRACKBAR_NAME = "Canny: Lower Threshold";
|
||||||
|
|
||||||
|
const float CARD_ASPECT_RATIO = 88.0f / 63.0f;
|
||||||
|
const std::string ASPECT_RATIO_TOLERANCE_TRACKBAR_NAME = "Aspect Ratio Tolerance";
|
||||||
|
int g_aspect_ratio_tolerance = 1;
|
||||||
|
const int MAX_ASPECT_RATIO_TOLERANCE = 100;
|
||||||
|
|
||||||
|
int g_Canny_lower_threshold = 110;
|
||||||
|
const int CANNY_UPPER_THRESHOLD = 255;
|
||||||
|
|
||||||
|
int main(int argc, char** argv ) {
|
||||||
|
cv::VideoCapture cap;
|
||||||
|
cap.open(0);
|
||||||
|
|
||||||
|
if (!cap.isOpened()) {
|
||||||
|
std::cerr << "Couldn't open capture" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Card aspect ratio: " << CARD_ASPECT_RATIO << std::endl;
|
||||||
|
|
||||||
|
cv::namedWindow(WINDOW_NAME);
|
||||||
|
|
||||||
|
cv::createTrackbar(CANNY_LOWER_THRESHOLD_TRACKBAR_NAME, WINDOW_NAME, &g_Canny_lower_threshold, CANNY_UPPER_THRESHOLD, NULL);
|
||||||
|
cv::createTrackbar(ASPECT_RATIO_TOLERANCE_TRACKBAR_NAME, WINDOW_NAME, &g_aspect_ratio_tolerance, MAX_ASPECT_RATIO_TOLERANCE, NULL);
|
||||||
|
|
||||||
|
cv::Mat frame, grayscaleFrame, blurFrame, cannyFrame;
|
||||||
|
while (true) {
|
||||||
|
cap >> frame;
|
||||||
|
|
||||||
|
cv::cvtColor(frame, grayscaleFrame, cv::COLOR_BGR2GRAY);
|
||||||
|
cv::GaussianBlur(grayscaleFrame, blurFrame, cv::Size(5, 5), 2, 2);
|
||||||
|
cv::Canny(blurFrame, cannyFrame, g_Canny_lower_threshold, CANNY_UPPER_THRESHOLD);
|
||||||
|
|
||||||
|
std::vector<std::vector<cv::Point> > contours;
|
||||||
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
|
cv::findContours(cannyFrame, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
|
||||||
|
|
||||||
|
std::vector<std::vector<cv::Point>> hull(contours.size());
|
||||||
|
for(size_t i = 0; i < contours.size(); i++) {
|
||||||
|
cv::convexHull(contours[i], hull[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cv::RotatedRect> minRect(contours.size());
|
||||||
|
for(size_t i = 0; i < contours.size(); i++) {
|
||||||
|
minRect[i] = cv::minAreaRect(contours[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//cv::Scalar contourColor = cv::Scalar(255, 0, 0);
|
||||||
|
cv::Scalar hullColor = cv::Scalar(0, 255, 0);
|
||||||
|
cv::Scalar rectangleColor = cv::Scalar(0, 0, 255);
|
||||||
|
|
||||||
|
for (size_t i = 0; i< contours.size(); i++) {
|
||||||
|
//cv::drawContours(frame, contours, (int)i, contourColor, 2, cv::LINE_8, hierarchy, 0);
|
||||||
|
//cv::drawContours(frame, hull, (int)i, hullColor, 2, cv::LINE_8);
|
||||||
|
|
||||||
|
// TODO: A purely aspect-ratio-based detection method returns too many false positives
|
||||||
|
// inside of a card, even after screwing around with various algorithm parameters.
|
||||||
|
// We have two potential options to fix this:
|
||||||
|
// - Only take the largest detected RotatedRect with the correct aspect ratio
|
||||||
|
// - Perform the camera calibration necessary to take accurate real-world measurements
|
||||||
|
float aspectRatio = minRect[i].size.height / minRect[i].size.width;
|
||||||
|
float aspectRatioTolerance = g_aspect_ratio_tolerance / 100.0f;
|
||||||
|
if (aspectRatio < (CARD_ASPECT_RATIO - aspectRatioTolerance) || aspectRatio > (CARD_ASPECT_RATIO + aspectRatioTolerance)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Point2f rect_points[4];
|
||||||
|
minRect[i].points(rect_points);
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
cv::line(frame, rect_points[j], rect_points[(j + 1) % 4], rectangleColor);
|
||||||
|
}
|
||||||
|
cv::putText(frame, std::to_string(aspectRatio), minRect[i].center, cv::FONT_HERSHEY_COMPLEX, 1, hullColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::imshow(WINDOW_NAME, frame);
|
||||||
|
|
||||||
|
char c = (char)cv::waitKey(33);
|
||||||
|
if (c == 27) {
|
||||||
|
break;
|
||||||
|
} else if (c == 's') {
|
||||||
|
cv::imwrite("output.png", frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::destroyWindow(WINDOW_NAME);
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
#include <opencv2/opencv.hpp>
|
|
||||||
|
|
||||||
const std::string WINDOW_NAME = "A Scanner Darkly";
|
|
||||||
const std::string LOWER_THRESHOLD_TRACKBAR_NAME = "Canny: Lower Threshold";
|
|
||||||
const std::string UPPER_THRESHOLD_TRACKBAR_NAME = "Canny: Upper Threshold";
|
|
||||||
|
|
||||||
int g_Canny_lower_threshold = 110;
|
|
||||||
int g_Canny_upper_threshold = 300;
|
|
||||||
|
|
||||||
int main(int argc, char** argv ) {
|
|
||||||
cv::VideoCapture cap;
|
|
||||||
cap.open(0);
|
|
||||||
|
|
||||||
if (!cap.isOpened()) {
|
|
||||||
std::cerr << "Couldn't open capture" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cv::namedWindow(WINDOW_NAME);
|
|
||||||
cv::createTrackbar(LOWER_THRESHOLD_TRACKBAR_NAME, WINDOW_NAME, &g_Canny_lower_threshold, 1000, NULL);
|
|
||||||
cv::createTrackbar(UPPER_THRESHOLD_TRACKBAR_NAME, WINDOW_NAME, &g_Canny_upper_threshold, 1000, NULL);
|
|
||||||
|
|
||||||
cv::Mat frame, grayscaleFrame, cannyFrame;
|
|
||||||
while (true) {
|
|
||||||
cap >> frame;
|
|
||||||
|
|
||||||
cv::cvtColor(frame, grayscaleFrame, cv::COLOR_BGR2GRAY);
|
|
||||||
cv::Canny(grayscaleFrame, cannyFrame, g_Canny_lower_threshold, g_Canny_upper_threshold);
|
|
||||||
|
|
||||||
cv::imshow(WINDOW_NAME, cannyFrame);
|
|
||||||
|
|
||||||
char c = (char)cv::waitKey(33);
|
|
||||||
if (c == 27) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cv::destroyWindow(WINDOW_NAME);
|
|
||||||
}
|
|
|
@ -1,7 +1,9 @@
|
||||||
createdb:
|
createdb:
|
||||||
mysql --user=root --password=$(shell pass show sevenkeys/mysql) <sql/createdb.sql
|
mysql --user=root --password=$(shell pass show sevenkeys/mysql) <sql/createdb.sql
|
||||||
import: createdb
|
import: createdb
|
||||||
go run main.go
|
go run cmd/importer/main.go
|
||||||
|
storagemgr:
|
||||||
|
go run cmd/storagemgr/main.go
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
mysql --user=root --password=$(shell pass show sevenkeys/mysql) <sql/removedb.sql
|
mysql --user=root --password=$(shell pass show sevenkeys/mysql) <sql/removedb.sql
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("storage manager")
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package entities
|
||||||
|
|
||||||
|
type CardStorageLocation struct {
|
||||||
|
Id int
|
||||||
|
CardPrintingId string
|
||||||
|
StorageBox string
|
||||||
|
Source string
|
||||||
|
Position int
|
||||||
|
}
|
|
@ -65,3 +65,31 @@ func InsertCard(db *sql.DB, card types.Card) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InsertCardStorageLocation(db *sql.DB, cardPrintingId string, storageBox string, source string) error {
|
||||||
|
var lastPosition int
|
||||||
|
getLastPositionQuery := `SELECT Position FROM CardStorageLocation WHERE StorageBox = ? ORDER BY Position DESC LIMIT 1;`
|
||||||
|
err := db.QueryRow(query, storageBox).Scan(&lastPosition)
|
||||||
|
|
||||||
|
var nextPosition int
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
nextPosition = 1
|
||||||
|
} else {
|
||||||
|
nextPosition = lastPosition + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
insertQuery := `INSERT INTO CardStorageLocation
|
||||||
|
(CardPrintingId, StorageBox, Source, Position)
|
||||||
|
VALUES (?, ?, ?, ?);`
|
||||||
|
insert, err := db.Prepare(insertQuery)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = insert.Exec(cardPrintingId, storageBox, source, nextPosition)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -27,3 +27,12 @@ CREATE TABLE IF NOT EXISTS CardPrinting (
|
||||||
CollectorNumber VARCHAR(10) NOT NULL,
|
CollectorNumber VARCHAR(10) NOT NULL,
|
||||||
Language VARCHAR(3) NOT NULL
|
Language VARCHAR(3) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS CardStorageLocation (
|
||||||
|
Id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
CardPrintingId VARCHAR(36) NOT NULL,
|
||||||
|
FOREIGN KEY (CardPrintingId) REFERENCES CardPrinting(Id),
|
||||||
|
StorageBox VARCHAR(20) NOT NULL,
|
||||||
|
Source VARCHAR(100) NULL,
|
||||||
|
Position INT NOT NULL
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue