This commit is contained in:
Jacob Signorovitch 2024-09-21 19:32:31 -04:00
commit 879cbc4a32
12 changed files with 213 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.o
obj/
*.out
.cache/
dataset/
testimgs/
compile_commands.json

29
Makefile Normal file
View File

@ -0,0 +1,29 @@
NAME = imgboxer
CXX = g++
CXXFLAGS = -Wall -std=c++11 `pkg-config --cflags opencv4`
LDFLAGS = `pkg-config --libs opencv4`
SRC_DIR = src
OBJ_DIR = obj
TARGET = $(NAME).out
SRC_FILES = $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES = $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES))
all: $(TARGET)
$(TARGET): $(OBJ_FILES)
@ echo -e "\x1b[32;1mLinking \x1b[0m\x1b[32m$(TARGET)\x1b[32;1m...\x1b[0m\x1b[37m $(CXX) -o $(TARGET) $(OBJ_FILES) $(LDFLAGS)\x1b[0m"
@ $(CXX) -o $(TARGET) $(OBJ_FILES) $(LDFLAGS)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/include/%.hpp
@ mkdir -p $(OBJ_DIR)
@ echo -e "\x1b[32;1mCompiling \x1b[0m\x1b[32m$<\x1b[32;1m... \x1b[0m\x1b[37m$(CXX) $(CXXFLAGS) -c $< -o $@\x1b[0m"
@ $(CXX) $(CXXFLAGS) -c $< -o $@
clean:
@ echo -e "\x1b[32;1mCleaning up...\x1b[0m"
@ rm -rf $(OBJ_DIR) $(TARGET)
.PHONY: all clean

23
src/bound.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "include/bound.hpp"
std::vector<std::vector<cv::Point>> bound_contours(cv::Mat img) {
std::vector<std::vector<cv::Point>> contours;
cv::findContours(img, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
return contours;
}
std::vector<cv::Rect>
bound_boxes(std::vector<std::vector<cv::Point>> contours) {
std::vector<cv::Rect> boxes;;
for (size_t i = 0; i < contours.size(); i++) {
cv::Rect box = cv::boundingRect(contours[i]);
if (box.width < BOUND_MIN_W && box.height < BOUND_MIN_H) continue;
boxes.push_back(box);
}
return boxes;
}

5
src/img.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "include/img.hpp"
cv::Mat img_get(char* fpath) {
return cv::imread(fpath, cv::IMREAD_GRAYSCALE);
}

17
src/include/bound.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef BOUND_H
#define BOUND_H
// Create bounding boxes and contours for images.
#include <opencv2/opencv.hpp>
#define BOUND_MIN_W 90
#define BOUND_MIN_H BOUND_MIN_W
// Return list of coutours.
std::vector<std::vector<cv::Point>> bound_contours(cv::Mat img);
// Return list of boxes.
std::vector<cv::Rect> bound_boxes(std::vector<std::vector<cv::Point>> contours);
#endif

10
src/include/img.hpp Normal file
View File

@ -0,0 +1,10 @@
#ifndef IMG_H
#define IMG_H
// Read in images.
#include <opencv2/opencv.hpp>
cv::Mat img_get(char* fpath);
#endif

15
src/include/main.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef MAIN_H
#define MAIN_H
#include <iostream>
#include <opencv2/opencv.hpp>
#include "img.hpp"
#include "preprocess.hpp"
#include "bound.hpp"
#include "yolo.hpp"
int main(int argc, char** argv);
#endif

View File

@ -0,0 +1,10 @@
#ifndef PREPROCESS_H
#define PREPROCESS_H
// Pre-process images (apply filters, grayscale, &c.)
#include <opencv2/opencv.hpp>
cv::Mat preprocess_threshold(cv::Mat img);
#endif

28
src/include/yolo.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef YOLO_H
#define YOLO_H
// Create the YOLOv8 image labels.
#include <stdlib.h>
#include <iostream>
#include <opencv2/opencv.hpp>
// Name to assign to all labels.
#define LABEL_NAME "tooth"
typedef struct Label {
int confidence;
int xmin;
int ymin;
int xmax;
int ymax;
} label_t;
label_t* yolo_mklabel(cv::Rect box);
// Write labels to file from cv::Rect.
void yolo_write_labels(char* fname, std::vector<cv::Rect> boxes);
#endif

41
src/main.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "include/main.hpp"
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
// Check for invalid invocation.
if (argc != 2) {
printf("%s IMAGE", argv[0]);
return -1;
}
// Read in image.
cv::Mat img = img_get(argv[1]);
// Check the image actually exists.
if (img.empty()) {
std::cout << "File not found: " << argv[1] << std::endl;
return -1;
}
// Threshold the image (in case it's not already binary).
cv::Mat binimg = preprocess_threshold(img);
vector<vector<Point>> contours = bound_contours(binimg);
vector<Rect> boxes = bound_boxes(contours);
for (size_t i = 0; i < contours.size(); i++) {
rectangle(img, boxes[i], Scalar(255, 255, 255), 1);
drawContours(img, contours, (int)i, Scalar(255, 255, 255), 1, LINE_8);
}
yolo_write_labels("asdf", boxes);
// Show image with bounding boxes.
imshow("Bounding Boxes", img);
waitKey(0);
return 0;
}

7
src/preprocess.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "include/preprocess.hpp"
cv::Mat preprocess_threshold(cv::Mat img) {
cv::Mat binimg;
cv::threshold(img, binimg, 128, 255, cv::THRESH_BINARY);
return binimg;
}

21
src/yolo.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "include/yolo.hpp"
label_t* yolo_mklabel(cv::Rect box) {
// why is c++ like this
label_t* label = (label_t*)malloc(sizeof(label_t));
label->confidence = 1;
label->xmin = box.x;
label->ymin = box.y;
label->xmax = box.x + box.width;
label->ymax = box.y + box.height;
return label;
}
void yolo_write_labels(char* fname, std::vector<cv::Rect> boxes) {
for (size_t i = 0; i < boxes.size(); i++) {
auto box = boxes[i];
printf("%s 1 %d %d %d %d\n", LABEL_NAME, box.x, box.y, box.x + box.width, box.y + box.height);
}
}