diff --git a/App/LicensePlates/LicensePlates.xcodeproj/project.xcworkspace/xcuserdata/maciej.xcuserdatad/UserInterfaceState.xcuserstate b/App/LicensePlates/LicensePlates.xcodeproj/project.xcworkspace/xcuserdata/maciej.xcuserdatad/UserInterfaceState.xcuserstate index 78b5e08..ac57e0e 100644 Binary files a/App/LicensePlates/LicensePlates.xcodeproj/project.xcworkspace/xcuserdata/maciej.xcuserdatad/UserInterfaceState.xcuserstate and b/App/LicensePlates/LicensePlates.xcodeproj/project.xcworkspace/xcuserdata/maciej.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/App/LicensePlates/LicensePlates.xcodeproj/xcuserdata/maciej.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/App/LicensePlates/LicensePlates.xcodeproj/xcuserdata/maciej.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 6d6c711..2b5fa34 100644 --- a/App/LicensePlates/LicensePlates.xcodeproj/xcuserdata/maciej.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/App/LicensePlates/LicensePlates.xcodeproj/xcuserdata/maciej.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,166 +3,4 @@ uuid = "D6BB566A-C242-4B4E-B55F-1FA78A3A061D" type = "1" version = "2.0"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/Contents.json b/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/Contents.json new file mode 100644 index 0000000..0634ddc --- /dev/null +++ b/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "plate.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/plate.png b/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/plate.png new file mode 100644 index 0000000..f0ead0a Binary files /dev/null and b/App/LicensePlates/LicensePlates/Assets.xcassets/plate.imageset/plate.png differ diff --git a/App/LicensePlates/LicensePlates/Controller/Api.swift b/App/LicensePlates/LicensePlates/Controller/Api.swift index da326d9..4401f7e 100644 --- a/App/LicensePlates/LicensePlates/Controller/Api.swift +++ b/App/LicensePlates/LicensePlates/Controller/Api.swift @@ -57,15 +57,75 @@ class Api { let myUIImage = responseData.imageFromBase64 - let image = Image(uiImage: myUIImage!) - ResponseData.shared.imageData = image - PlatesList.shared.imagesList.append(LicensePlateItem(image: image)) + let new_image = Image(uiImage: myUIImage!) + ResponseData.shared.imageData = new_image + PlatesList.shared.imagesList.append(LicensePlateItem(image: new_image)) // using UserDefaults // PlatesList.shared.imagesBase64List.append(myUIImage!.base64!) // UserDefaults.standard.set(PlatesList.shared.imagesBase64List, forKey: "platesList") ResponseData.shared.uiImageData = myUIImage! + self.getPlatsNumberResponse(image: image) { res in + if res == true { + completion(true) + } else { + completion(false) + } + } + } else { + completion(false) + } + + } catch { + print("Error: \(error)") + completion(false) + } + + + } else { + completion(false) + } + case.failure: + completion(false) + } + } + } + + func getPlatsNumberResponse(image: String, completion: @escaping(Bool?) -> Void) { + let parameters = ["imageFile": image] as [String : Any] + + session.request("http://192.168.5.129:8080/getPlatesNumber", method: .post, parameters: parameters as Parameters, encoding: JSONEncoding.default, headers: nil) + .response { response in + switch response.result { + case.success: + if response.response?.statusCode == 200 { + let jsonData = response.data + do { + let allReplies = try JSONDecoder().decode(PlatesNumberItem.self, from: jsonData!) + + if allReplies.platesNumber != ["None"] { +// responseData = responseData.replacingOccurrences(of: "b'", with: "") +// responseData = String(responseData.replacingOccurrences(of: "\'", with: "")) +// responseData = responseData.fixedBase64Format + + for n in allReplies.platesNumber { + PlatesList.shared.platesNumberList.append(n) + } + + UserDefaults.standard.set(PlatesList.shared.platesNumberList, forKey: "platesList") + +// let myUIImage = responseData.imageFromBase64 + +// let image = Image(uiImage: myUIImage!) +// ResponseData.shared.imageData = image +// PlatesList.shared.imagesList.append(LicensePlateItem(image: image)) + + // using UserDefaults +// PlatesList.shared.imagesBase64List.append(myUIImage!.base64!) +// UserDefaults.standard.set(PlatesList.shared.imagesBase64List, forKey: "platesList") + +// ResponseData.shared.uiImageData = myUIImage! completion(true) } else { completion(false) diff --git a/App/LicensePlates/LicensePlates/Data/PlatesList.swift b/App/LicensePlates/LicensePlates/Data/PlatesList.swift index e997de1..c694661 100644 --- a/App/LicensePlates/LicensePlates/Data/PlatesList.swift +++ b/App/LicensePlates/LicensePlates/Data/PlatesList.swift @@ -10,6 +10,8 @@ import SwiftUI class PlatesList : ObservableObject { @Published var imagesList: [LicensePlateItem] = [LicensePlateItem]() + @Published var platesNumberList: [String] = UserDefaults.standard.stringArray(forKey: "platesList") ?? [String]() + // using UserDefaults // @Published var imagesBase64List: [String] = UserDefaults.standard.stringArray(forKey: "platesList") ?? [String]() diff --git a/App/LicensePlates/LicensePlates/Model/LicensePlateItem.swift b/App/LicensePlates/LicensePlates/Model/LicensePlateItem.swift index 540dfda..77da880 100644 --- a/App/LicensePlates/LicensePlates/Model/LicensePlateItem.swift +++ b/App/LicensePlates/LicensePlates/Model/LicensePlateItem.swift @@ -12,3 +12,7 @@ struct LicensePlateItem { var id = UUID() var image: Image } + +struct PlatesNumberItem: Codable { + var platesNumber: [String] +} diff --git a/App/LicensePlates/LicensePlates/View/ContentView.swift b/App/LicensePlates/LicensePlates/View/ContentView.swift index b13af19..7715ed4 100644 --- a/App/LicensePlates/LicensePlates/View/ContentView.swift +++ b/App/LicensePlates/LicensePlates/View/ContentView.swift @@ -197,3 +197,23 @@ extension String { return UIImage(data: imageData) } } + +struct ImageOverlay: View { + + var number: String + + init(_ number: String) { + self.number = number + } + + var body: some View { + ZStack { + + Text(number) + .font(.system(size: 50)) + .font(.callout) + .padding(.trailing, 30) + .foregroundColor(.black) + } + } +} diff --git a/App/LicensePlates/LicensePlates/View/MenuView.swift b/App/LicensePlates/LicensePlates/View/MenuView.swift index a5e82ea..26275d3 100644 --- a/App/LicensePlates/LicensePlates/View/MenuView.swift +++ b/App/LicensePlates/LicensePlates/View/MenuView.swift @@ -12,7 +12,7 @@ struct MenuView: View { TabView { ContentView() .tabItem { - Image(systemName: "viewfinder") + Image(systemName: "camera") Text("Photo") } PlatesListView() diff --git a/App/LicensePlates/LicensePlates/View/PlatesListView.swift b/App/LicensePlates/LicensePlates/View/PlatesListView.swift index b45a7e9..2b7f955 100644 --- a/App/LicensePlates/LicensePlates/View/PlatesListView.swift +++ b/App/LicensePlates/LicensePlates/View/PlatesListView.swift @@ -15,21 +15,45 @@ struct PlatesListView: View { var body: some View { NavigationView { VStack { - if imagesList.imagesList.isEmpty { + if imagesList.platesNumberList.isEmpty { Text("No history") } else { List { - ForEach(imagesList.imagesList, id: \.id) { item in - item.image + ForEach(imagesList.platesNumberList, id: \.self) { item in + Image("plate") .resizable() .scaledToFit() - .padding() + .overlay(ImageOverlay(item), alignment: .trailing) + +// item.image +// .resizable() +// .scaledToFit() +// .padding() + } } } } + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button { + isPresented.toggle() + } label: { + Image(systemName: "trash") + } + } + } + .alert(isPresented: $isPresented, content: { + Alert(title: Text("Do you want to delete the history?"), + primaryButton: .default(Text("No")){ + }, + secondaryButton:.default(Text("Yes")) { + UserDefaults.standard.set([String](), forKey: "platesList") + imagesList.platesNumberList = UserDefaults.standard.stringArray(forKey: "platesList") ?? [String]() + }) + }) // using UserDefaults // VStack { diff --git a/api.py b/api.py index 18acceb..6d3e708 100644 --- a/api.py +++ b/api.py @@ -13,6 +13,8 @@ app = Flask(__name__) """ Automatic call while FLASK init """ +# def deinit_yolo(yolo): +# yolo.close_session() """API_address/ping/""" @app.route("/ping/", methods=["GET"]) @@ -27,12 +29,10 @@ def test(): o = {'str': 'okokok'} return jsonify(o), 200 -"""API_address/detectLicense?img=""" -@app.route("/detectLicense", methods=['POST']) -def detectLicensePlate(): +@app.route('/getPlatesNumber', methods=['POST']) +def getPlatesNumber(): yolo_model = YOLO() res = json.loads(request.data) - print('ok') # decoded data decoded_data = base64.b64decode(res["imageFile"]) @@ -40,9 +40,23 @@ def detectLicensePlate(): img_file.write(decoded_data) img_file.close() image_path = r'base64.png' - base64_b = yolo_video.detect_license_plate(model=yolo_model, img_path=image_path, i=0) - print(type(str(base64_b))) - res = {'str': str(base64_b)} + base64_b, texts = yolo_video.detect_license_plate(model=yolo_model, img_path=image_path, i=0) + res = {'platesNumber': texts} + return jsonify(res), 200 + +"""API_address/detectLicense?img=""" +@app.route("/detectLicense", methods=['POST']) +def detectLicensePlate(): + yolo_model = YOLO() + res = json.loads(request.data) + + # decoded data + decoded_data = base64.b64decode(res["imageFile"]) + img_file = open('base64.png', 'wb') + img_file.write(decoded_data) + img_file.close() + image_path = r'base64.png' + base64_b, texts = yolo_video.detect_license_plate(model=yolo_model, img_path=image_path, i=0) return jsonify(str(base64_b)), 200 if __name__ == '__main__': diff --git a/yolo_video.py b/yolo_video.py index 4b3bbe8..0278800 100644 --- a/yolo_video.py +++ b/yolo_video.py @@ -64,20 +64,36 @@ def compute_skew(src_img): def deskew(src_img): return rotate_image(src_img, compute_skew(src_img)) +from keras import backend as K + + def detect_img(yolo, img_path, j): try: + # processed_image = cv.imread(img_path) + # final_image = cv.imread(img_path) + # processed_image = cv.resize(processed_image, (3024,3024)) + # img_path = './img_to_detect.jpeg' + # cv.imwrite(img_path, processed_image) image = Image.open(img_path) except: print('Image open Error! Try again!') return None else: + # Before prediction + # K.clear_session() + r_image, pred = yolo.detect_image(image) + + # After prediction + # K.clear_session() + r_image.save('detected.png') processed_image = cv.imread(img_path) if not pred: return None i = 0 + texts = [] ## FIXME : better list mapping for prediction in pred: x1 = prediction[1][0] @@ -86,17 +102,36 @@ def detect_img(yolo, img_path, j): y2 = prediction[2][1] w = abs(x1 - x2) h = abs(y1 - y2) + # print(pred) + # print(f'x1: {x1}, x2: {x2}, y1: {y1}, y2: {y2}, w: {w}, h: {h}') img = processed_image[y1:y1 + h, x1:x1 + w] img = deskew(img) + # gray_image = cv.cvtColor(robot_img, cv.COLOR_BGR2GRAY) + # # gray_image = cv.bilateralFilter(gray_image, 11, 17, 17) + # gaussian_blur = cv.GaussianBlur(gray_image, (9, 9), 0) + # edged = cv.Canny(gaussian_blur, 255, 255) + # + # image_file = './img0.png' + # img = cv.imread(image_file) + gray_image = grayscale(img) - thresh, im_bw = cv.threshold(gray_image, 125, 150, cv.THRESH_BINARY) + thresh, im_bw = cv.threshold(gray_image, 125, 150, cv.THRESH_BINARY) #the best = 120,150; 100, 150; 150, 210 no_noise = noise_removal(im_bw) no_borders = remove_borders(no_noise) + # blur = cv.GaussianBlur(gray_image, (3, 3), 0) + # thresh = cv.threshold(blur, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1] + # + # # Morph open to remove noise and invert image + # kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) + # opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=1) + # no_borders = 255 - no_borders + cv.imwrite(f'img/img{j}{i}.png', no_borders) text = ocr.get_text_from_image(f'img/img{j}{i}.png') + texts.append(text) if i > 0: processed_image = cv.imread(f'final/final{j}{i-1}.png') res = cv.rectangle(processed_image, (x1, y1), (x1+w, y1+h), (0, 0, 255), 15) @@ -104,13 +139,36 @@ def detect_img(yolo, img_path, j): cv.imwrite(f'final/final{j}{i}.png', res) my_string = 'ok' i += 1 + # with open("final.png", "rb") as img_file: + # my_string = base64.b64encode(img_file.read()) + # print(my_string) with open(f"final/final{j}{i-1}.png", "rb") as img_file: my_string = base64.b64encode(img_file.read()) - return my_string + return my_string, texts + + # text_file = open("base64.txt", "w") + # text_file.write(str(my_string)) + # text_file.close() + + # decoded data + # decoded_data = base64.b64decode((my_string)) + # img_file = open('base64.png', 'wb') + # img_file.write(decoded_data) + # img_file.close() def detect_license_plate(model, img_path, i): - str = detect_img(model, img_path, i) - if not str: - return None + str, texts = detect_img(model, img_path, i) + if not str or not texts: + return None, [None] - return str + return str, texts + +# yolo_model = YOLO() +# for i in range(18,100): +# image_path = rf'Images/New/IMG_25{i}.jpeg' #95; 3909, 2491 +# detect_license_plate(model=yolo_model, img_path=image_path, i=i) +# image_path = rf'./Images/New/IMG_5016.jpeg' #95; 3909, 2491 +# detect_license_plate(model=yolo_model, img_path=image_path, i=0) +# print(ocr.get_text_from_image(f'img0.png')) +# print(ocr.keras_ocr_func()) +# print(ocr.tesseract_ocr()) \ No newline at end of file