如何使用IOS DJI-SDK以编程方式从无人机下载图像 [英] How to programmatically download Images from drone using the IOS DJI-SDK
问题描述
我遇到了一些问题,将无人机中的图像直接下载到应用程序中.尝试下载图像时,出现"系统繁忙,请稍后重试.(代码:-1004)"的错误信息.找不到解决此问题的任何方法.
I've been having some issues downloaded images from my drone directly to my application. I keep getting a "System is busy, please retry later.(code:-1004)" error message when attempting to download the image, I have checked the DJI forum and other questions here on stackoverflow and have not been able to find any solution to this problem.
我已经看过这个问题,但我已经在使用该答案中建议的技术.
I've already taken a look at this question, but i'm already using the technique suggested from that answer.
这是我编写的用于下载图像的功能:
Here is the function I've written to download the images:
func downloadFilesFromDrone(){
// get current product
guard let drone = DJISDKManager.product() else {
Logger.logError("Product is connected but DJISDKManager.product is nil when attempting to download media")
return
}
// Get camera on drone
guard let camera: DJICamera = drone.camera else {
Logger.logError("Unable to detect Camera in downloadFilesFromDrone()")
// make recursive call until we are able to detect the camera
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Logger.logH1("Trying to detect Camera again")
self.downloadFilesFromDrone()
}
return
}
Logger.logH1("Successfully detected the camera")
// check if we can download images with the product
if !camera.isMediaDownloadModeSupported() {
Logger.logError("Product does not support media download mode")
return
}
// switch camera mode to allow for media downloads
camera.setMode( .mediaDownload, withCompletion: {(error) in
if error != nil {
print("\(error!.localizedDescription)")
}
else {
// get the media manager from the drone to gain access to the files
let manager = camera.mediaManager!
manager.refreshFileList(completion: { (error) in
if error != nil {
print("State: \(manager.fileListState.rawValue)")
print("Error refreshing list: \(error!.localizedDescription)")
}
else {
Logger.logH1("Refreshed file list")
print("State: \(manager.fileListState.rawValue)")
guard let files = manager.fileListSnapshot() else {
Logger.logError("No files to download")
return
}
Logger.logH1("There are files to download")
var images: [UIImage] = []
for file in files {
if file.mediaType == .JPEG {
print("Time created: \(file.timeCreated)")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
file.fetchData(withOffset: 0, update: DispatchQueue.main, update: {(_ data: Data?, _ isComplete: Bool, _ error: Error?) -> Void in
if error != nil {
print("State: \(manager.fileListState.rawValue)")
print("Error downloading photo: \(error!)")
}
else {
// unwrap downloaded data and create image
if let data = data, let downloadedImage = UIImage(data: data) {
print("Image was downloaded!")
images.append( downloadedImage )
}
}
}) // end of filedata fetch
}
}
} // end of loop
}
}) // end of file-refresh block
}
})// end of camera setMode block
}
这是在用无人机测试时此功能的输出:
And here is the output of this function when testing with my drone:
*** Product Connected ***
*** Unable to detect Camera in downloadFilesFromDrone() ***
*** Firmware package version is: Unknown ***
--> Trying to detect Camera again
--> Successfully detected the camera
--> Refreshed file list
State: 0
--> There are files to download
Time created: 2017-09-01 15:17:04
Time created: 2017-09-01 15:17:16
Time created: 2017-09-01 15:17:26
Time created: 2017-09-01 15:17:36
Time created: 2017-09-01 15:19:06
State: 0
Error downloading photo: System is busy, please retry later.(code:-1004)
State: 0
Error downloading photo: System is busy, please retry later.(code:-1004)
State: 0
Error downloading photo: System is busy, please retry later.(code:-1004)
State: 0
Error downloading photo: System is busy, please retry later.(code:-1004)
下面是我用来从无人机下载图像的代码.
/**
* This function downloads the N latest images from the drone and passes them to the completionhandler once all images have completed downloading
*/
func downloadImages( files: [DJIMediaFile], howMany: Int, maxErrors: Int, completion: @escaping ([UIImage]) -> Void){
Logger.logH1("Queueing \(howMany) image(s) to be downloaded")
func downloadNextImage( files: [DJIMediaFile], fileCount: Int, index: Int = 0, downloadedFiles: [UIImage] = [], errorCount: Int = 0) {
// stop when we reach the end of the list
if index == fileCount {
completion(downloadedFiles)
return
}
else {
var imageData: Data?
let file = files[index]
file.fetchData(withOffset: 0, update: DispatchQueue.main, update: {(_ data: Data?, _ isComplete: Bool, _ error: Error?) -> Void in
if let error = error {
Logger.logError("\(error)")
if errorCount < maxErrors {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Logger.logH1("Attempting to download: \(file.fileName) again")
downloadNextImage(files: files, fileCount: fileCount, index: index, downloadedFiles: downloadedFiles, errorCount: errorCount + 1)
}
}
else {
Logger.logError("Too many errors downloading the images, try downloading again")
}
}
else {
// if image is done downloading
if isComplete {
// get full image data
if let imageData = imageData, let image = UIImage(data: imageData) {
Logger.logH1("Downloaded: \(file.fileName)")
// now that the image is done downloading, move onto the next image
downloadNextImage(files: files, fileCount: fileCount, index: (index + 1), downloadedFiles: downloadedFiles + [image], errorCount: 0)
}
}
// else, download the file
else {
// If image exists, append the data
if let _ = imageData, let data = data {
imageData?.append(data)
}
// initialize the image data
else {
imageData = data
}
}
}
}) // end of filedata fetch
} // end of else statement
}
// bounds checking
let available = files.count
let n = howMany > available ? available : howMany
// grab the N latest images taken by the drone
let filesToDownload : [DJIMediaFile] = Array ( files.suffix(n) )
// start the recursive function
downloadNextImage(files: filesToDownload, fileCount: filesToDownload.count)
}
这是怎么称呼它:
// get current product
guard let drone = DJISDKManager.product() else {
Logger.logError("Product is connected but DJISDKManager.product is nil when attempting to download media")
return
}
// Get camera on drone
guard let camera: DJICamera = drone.camera else {
Logger.logError("Unable to detect Camera in initDownload()")
return
}
Logger.logH1("Successfully detected the camera")
// check if we can download images with the product
if !camera.isMediaDownloadModeSupported() {
Logger.logError("Product does not support media download mode")
return
}
// switch camera mode to allow for media downloads
camera.setMode( .mediaDownload, withCompletion: {(error) in
if error != nil {
print("\(error!.localizedDescription)")
}
else {
// get the media manager from the drone to gain access to the files
let manager = camera.mediaManager!
manager.refreshFileList(completion: { (error) in
if error != nil {
print("State: \(manager.fileListState.rawValue)")
print("Error refreshing list: \(error!.localizedDescription)")
}
else {
Logger.logH1("Refreshed file list")
print("State: \(manager.fileListState.rawValue)")
// get list of files
guard let files = manager.fileListSnapshot() else {
Logger.logError("No files to download")
return
}
Logger.logH1("There are files to download.. Beginning Download")
self.downloadImages(files: files, howMany: waypoints, maxErrors: 4, completion: { images in
Logger.logH1("Finished downloading: \(images.count) image(s)")
// do something with the images here
})
}
}) // end of file-refresh block
}
})// end of camera setMode block
推荐答案
您在这里遇到了两个问题.首先,您的updateBlock不足,因为它假设所有数据都将在一个调用中出现.请更仔细地查看 fetchData 的文档 a>()
You've got two problems here. Firstly, your updateBlock is inadequate because it's assuming that all the data will come in a single call. Look more carefully at the documentation for fetchData()
请注意updateBlock的定义:阻止接收文件数据.将被多次调用,每次将返回自上次调用以来接收到的数据."
Note the definition of updateBlock: "Block to receive file data. It will be called multiple times and each time will return the data received since the last call."
因此,您的updateBlock需要执行以下操作:
So your updateBlock needs to do something like this:
imageData.append(data)
if isComplete {
image = UIImage(data: imageData)
// handle image as desired
}
第二个问题是您正在同时请求所有文件的异步下载.您一次只需要下载一个文件,并且仅在上一个文件完成后才开始下一个文件.例如:
The second problem is that you are requesting the asynchronous download of all the files simultaneously. You need to download only one file at a time, and only start the next one after the previous one is complete. For example:
imageData.append(data)
if isComplete {
image = UIImage(data: imageData)
// handle image as desired
// then, initiate next download
downloadFilesFromDrone()
}
这篇关于如何使用IOS DJI-SDK以编程方式从无人机下载图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!