-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
417a5d6
commit 77d8f3a
Showing
16 changed files
with
416 additions
and
11 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[submodule "thirdparty/tesseract"] | ||
path = thirdparty/tesseract | ||
url = https://github.com/tesseract-ocr/tesseract | ||
[submodule "thirdparty/tesseract-ocr-ios"] | ||
path = thirdparty/tesseract-ocr-ios | ||
url = https://github.com/gali8/Tesseract-OCR-iOS |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
cmake_minimum_required(VERSION 3.10) | ||
|
||
project(CVPuzzleSolver_iOS LANGUAGES CXX Swift) | ||
|
||
set(APP_VERSION 1.0.0) | ||
set(APP_VERSION_SHORT 1.0) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
|
||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
|
||
if(NOT XCODE) | ||
message(FATAL_ERROR "Must use Xcode for building iOS app") | ||
endif() | ||
|
||
file(GLOB_RECURSE SOURCES src/*.cpp src/*.mm src/*.swift) | ||
# list(APPEND SOURCES include/UBHackingFall2023-Bridging-Header.h) | ||
|
||
# UBHackingFall2023-Bridging-Header.h | ||
# UBHackingFall2023-Briging-Header.h | ||
|
||
|
||
set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS} -import-objc-header ${CMAKE_CURRENT_SOURCE_DIR}/include/UBHackingFall2023-Bridging-Header.h") | ||
|
||
set(APP_BUNDLE_IDENTIFIER "ubh-fall2023-puzzles") | ||
set(APP_BUNDLE_NAME "${PROJECT_NAME}") | ||
set(APP_VERSION "${APP_VERSION}") | ||
set(APP_LONG_VERSION_STRING "${APP_VERSION}") | ||
set(APP_SHORT_VERSION_STRING "${APP_VERSION_SHORT}") | ||
set(APP_COPYRIGHT "Copyright © 2023 Peter Lilley and Sam Chen. All rights reserved.") | ||
set(APP_APP_CATEGORY "public.app-category.games") | ||
set(APP_BUNDLE_ICON_FILE "bundle_icon.icns") | ||
|
||
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SOURCES}) | ||
|
||
target_link_libraries(${PROJECT_NAME} PUBLIC solver) | ||
target_include_directories(${PROJECT_NAME} PUBLIC include) | ||
|
||
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" RESOURCE "${RESOURCES}") | ||
|
||
set(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/tesseract/tessdata/eng.traineddata) | ||
target_sources(${PROJECT_NAME} PUBLIC ${RESOURCES}) | ||
|
||
set_source_files_properties(${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>NSCameraUsageDescription</key> | ||
<string>Required for detecting sudoku puzzles!</string> | ||
<key>UIViewControllerBasedStatusBarAppearance</key> | ||
<false/> | ||
<key>CFBundleDevelopmentRegion</key> | ||
<string>en</string> | ||
<key>CFBundleExecutable</key> | ||
<string>${PROJECT_NAME}</string> | ||
<key>CFBundleIdentifier</key> | ||
<string>${APP_BUNDLE_IDENTIFIER}</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>${APP_BUNDLE_NAME}</string> | ||
<key>CFBundlePackageType</key> | ||
<string>APPL</string> | ||
<key>CFBundleShortVersionString</key> | ||
<string>${APP_SHORT_VERSION_STRING}</string> | ||
<key>CFBundleLongVersionString</key> | ||
<string>${APP_LONG_VERSION_STRING}</string> | ||
<key>CFBundleVersion</key> | ||
<string>${APP_VERSION}</string> | ||
<key>NSHumanReadableCopyright</key> | ||
<string>${APP_COPYRIGHT}</string> | ||
<key>LSRequiresIPhoneOS</key> | ||
<true/> | ||
<key>UIRequiredDeviceCapabilities</key> | ||
<array> | ||
<string>armv7</string> | ||
</array> | ||
<key>UIStatusBarHidden</key> | ||
<true/> | ||
<key>UISupportedInterfaceOrientations</key> | ||
<array> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
</array> | ||
<key>UISupportedInterfaceOrientations~ipad</key> | ||
<array> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
<string>UIInterfaceOrientationPortraitUpsideDown</string> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
</array> | ||
</dict> | ||
</plist> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
#import <solver_bridge.h> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#import <Foundation/Foundation.h> | ||
#import <UIKit/UIKit.h> | ||
#import <CoreGraphics/CGImage.h> | ||
|
||
@interface PuzzleSolverBridge : NSObject | ||
|
||
- (UIImage *) detectBoardIn: (UIImage *) image; | ||
|
||
- (NSArray *) solvePuzzle: (UIImage *) image; | ||
|
||
@end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import SwiftUI | ||
import AVFoundation | ||
|
||
// Global variables... don't judge me it's a hackathon!! | ||
var imageView = UIImageView(image: UIImage()) | ||
var puzzleSolverBridge = PuzzleSolverBridge() | ||
|
||
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { | ||
private var captureSession: AVCaptureSession = AVCaptureSession() | ||
private let videoDataOutput = AVCaptureVideoDataOutput() | ||
|
||
private func setupCamera() { | ||
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDualCamera, .builtInTrueDepthCamera], mediaType: .video, position: .back).devices.first else { | ||
fatalError("No back camera device found, please make sure to run SimpleLaneDetection in an iOS device and not a simulator") | ||
} | ||
let cameraInput = try! AVCaptureDeviceInput(device: device) | ||
self.captureSession.addInput(cameraInput) | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
imageView.bounds = view.bounds | ||
imageView.center = self.view.center; | ||
imageView.contentMode = .scaleToFill | ||
self.view.addSubview(imageView) | ||
|
||
self.setupCamera() | ||
self.setupVideo() | ||
self.captureSession.startRunning() | ||
} | ||
|
||
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { | ||
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } | ||
CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly) | ||
let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer) | ||
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer) | ||
let width = CVPixelBufferGetWidth(imageBuffer) | ||
let height = CVPixelBufferGetHeight(imageBuffer) | ||
let colorSpace = CGColorSpaceCreateDeviceRGB() | ||
|
||
var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue | ||
bitmapInfo |= CGImageAlphaInfo.premultipliedFirst.rawValue & CGBitmapInfo.alphaInfoMask.rawValue | ||
|
||
let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) | ||
guard let quartzImage = context?.makeImage() else { | ||
return | ||
} | ||
|
||
CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly) | ||
let input = UIImage(cgImage: quartzImage) | ||
|
||
// Call the Objective-C which calls the C++! | ||
let output = puzzleSolverBridge.detectBoard(in: input) | ||
|
||
DispatchQueue.main.async { | ||
imageView.image = output | ||
} | ||
} | ||
|
||
private func setupVideo() { | ||
videoDataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString) : NSNumber(value: kCVPixelFormatType_32BGRA)] as [String : Any] | ||
videoDataOutput.alwaysDiscardsLateVideoFrames = true | ||
videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "camera.frame.processing.queue")) | ||
self.captureSession.addOutput(videoDataOutput) | ||
guard let connection = self.videoDataOutput.connection(with: AVMediaType.video), connection.isVideoOrientationSupported else { | ||
return | ||
} | ||
connection.videoOrientation = .portrait | ||
} | ||
} | ||
|
||
// This is so stupid but it's required for SwiftUI... D: | ||
struct ViewControllerRepresentable: UIViewControllerRepresentable { | ||
func makeUIViewController(context: Context) -> ViewController { | ||
return ViewController() | ||
} | ||
|
||
func updateUIViewController(_ uiViewController: ViewController, context: Context) { | ||
|
||
} | ||
} | ||
|
||
enum AppState { | ||
case camera | ||
case solved | ||
} | ||
|
||
|
||
var solved = "" | ||
|
||
struct ContentView: View { | ||
@State private var appState = AppState.camera | ||
|
||
var body: some View { | ||
if (appState == AppState.camera) { | ||
VStack { | ||
ViewControllerRepresentable() | ||
Button(action: { | ||
let a = puzzleSolverBridge.solvePuzzle(imageView.image) | ||
if (a != nil && a!.count == 81) { | ||
appState = AppState.solved | ||
|
||
for i in 0..<a!.count { | ||
let v = (a![i] as! NSNumber).intValue | ||
if (i == 80) { | ||
solved += "\(v)" | ||
} | ||
else if (i % 9 == 8) { | ||
solved += "\(v)\n" | ||
} | ||
else { | ||
solved += "\(v) " | ||
} | ||
} | ||
} | ||
}) { | ||
Text("Solve") | ||
.foregroundColor(.white) | ||
.padding() | ||
} | ||
.background(RoundedRectangle(cornerRadius: 10.0).fill(Color.blue)) | ||
.padding() | ||
} | ||
} | ||
else { | ||
VStack { | ||
Text("Solution!") | ||
.font(Font.title) | ||
Text("\(solved)") | ||
Button(action: { | ||
appState = AppState.camera | ||
solved = "" | ||
}) { | ||
Text("Done") | ||
.foregroundColor(.white) | ||
.padding() | ||
} | ||
.background(RoundedRectangle(cornerRadius: 10.0).fill(Color.blue)) | ||
.padding() | ||
|
||
} | ||
} | ||
} | ||
} | ||
|
||
#Preview { | ||
ContentView() | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// swiftui_testApp.swift | ||
// swiftui_test | ||
// | ||
// Created by Peter P Lilley III on 11/3/23. | ||
// | ||
|
||
import SwiftUI | ||
|
||
@main | ||
struct PuzzlesApp: App { | ||
var body: some Scene { | ||
WindowGroup { | ||
ContentView() | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#import <solver_bridge.h> | ||
#include <opencv2/opencv.hpp> | ||
#import <opencv2/imgcodecs/ios.h> | ||
#import <Foundation/Foundation.h> | ||
#include <solver/board_detection.h> | ||
#include <solver/solver.h> | ||
|
||
@implementation PuzzleSolverBridge | ||
|
||
- (UIImage *) detectBoardIn: (UIImage *) image { | ||
cv::Mat image_mat; | ||
UIImageToMat(image, image_mat, true); | ||
if (image_mat.empty()) { | ||
return nullptr; | ||
} | ||
|
||
cv::cvtColor(image_mat, image_mat, cv::COLOR_RGBA2BGR); | ||
|
||
cv::Mat frame = prepare_frame(image_mat); | ||
std::array<cv::Point2f, 4> corners = find_corners(frame); | ||
cv::line(image_mat, corners[0], corners[1], cv::Scalar(0, 255, 0), 4); | ||
cv::line(image_mat, corners[1], corners[2], cv::Scalar(0, 255, 0), 4); | ||
cv::line(image_mat, corners[2], corners[3], cv::Scalar(0, 255, 0), 4); | ||
cv::line(image_mat, corners[3], corners[0], cv::Scalar(0, 255, 0), 4); | ||
|
||
|
||
return MatToUIImage(image_mat); | ||
} | ||
|
||
- (NSArray *) solvePuzzle: (UIImage *) image { | ||
cv::Mat image_mat; | ||
UIImageToMat(image, image_mat, true); | ||
|
||
std::optional<SudokuGrid> _grid = puzzle_solver(image_mat); | ||
if (!_grid) { | ||
return nullptr; | ||
} | ||
|
||
SudokuGrid grid = _grid.value(); | ||
|
||
NSMutableArray *result = [[NSMutableArray alloc] init]; | ||
for (int x = 0; x < 9; x++) { | ||
for (int y = 0; y < 9; y++) { | ||
[result addObject: [NSNumber numberWithInt: grid[x][y]]]; | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
@end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import SwiftUI | ||
import AVFoundation | ||
|
||
|
||
//struct ViewfinderView: View { | ||
// let camera = Camera() | ||
// | ||
// @Published var viewfinderImage: Image? | ||
// | ||
// init() { | ||
// Task { | ||
// await updateCamera() | ||
// } | ||
// } | ||
// | ||
// func updateCamera() async { | ||
// let stream = camera.stream.map { $0.image } | ||
// | ||
// for await image | ||
// } | ||
// | ||
//} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.