Browse Source

Face

master
marcoschmickler 4 days ago
parent
commit
c45a9d034a
  1. 271
      kplayer/detail/EditItemView.swift

271
kplayer/detail/EditItemView.swift

@ -12,7 +12,7 @@ protocol EditItemDelegate {
func setEnd()
func cancelEdit()
func okEdit()
func seek(_ : Double)
func seek(_: Double)
}
struct TagEditor: View {
@ -36,8 +36,7 @@ struct TagEditor: View {
Button(action: {
if item.tags.contains(tag) {
item.tags.removeAll(where: { toRemove in toRemove == tag })
}
else {
} else {
item.tags.append(tag)
}
if let c = self.completionHandler {
@ -49,12 +48,13 @@ struct TagEditor: View {
.padding(8)
.background(
RoundedRectangle(cornerRadius: 8)
.fill( item.tags.contains(tag) ?
.fill(item.tags.contains(tag) ?
Color.yellow.opacity(0.4) :
Color.gray.opacity(0.4)
)
)
}).buttonStyle(BorderlessButtonStyle())
})
.buttonStyle(BorderlessButtonStyle())
}
}
}
@ -69,6 +69,33 @@ struct EditItemView: View {
@State
var snap = true
@State
var processedImageURL: String?
@State
var isProcessing = false
@State
var showProcessedImage = false
@State
var loadedImage: UIImage?
@State
var imageLoadError: String?
@State
var imageScale: CGFloat = 1.0
@State
var imageOffset: CGSize = .zero
@State
var lastScale: CGFloat = 1.0
@State
var lastOffset: CGSize = .zero
var len: Double
var delegate: EditItemDelegate
@ -83,7 +110,7 @@ struct EditItemView: View {
set: {
scrubber = $0
delegate.seek($0)
print ($0)
print($0)
}
), in: item.time...(item.time + item.length))
@ -91,69 +118,78 @@ struct EditItemView: View {
Text("Start \(EditItemView.formatSecondsToString(item.time)) End \(EditItemView.formatSecondsToString(item.time + item.length)) Length \(item.length, specifier: "%.1f")")
HStack {
Stepper(value: Binding<Double>(
get: { item.time },
set: { s in
item.time = s
delegate.seek(item.time)
}), in: 0...len){
get: { item.time },
set: { s in
item.time = s
delegate.seek(item.time)
}), in: 0...len) {
Button(action: delegate.setStart, label: {
Text("Start")
}).buttonStyle(BorderlessButtonStyle());
})
.buttonStyle(BorderlessButtonStyle());
}
Stepper(value:Binding<Double>(
Stepper(value: Binding<Double>(
get: { item.length },
set: { l in
item.length = l
delegate.seek(item.time + item.length)
}
), in: 1...500){
), in: 1...500) {
Text("Len")
}
Button(action: delegate.setEnd, label: {
Text("End")
}).buttonStyle(BorderlessButtonStyle());
})
.buttonStyle(BorderlessButtonStyle());
}
Text("Zoom \(item.scale, specifier: "%.1f") X \(item.offset.x, specifier: "%.1f") Y \(item.offset.y, specifier: "%.1f") ")
HStack {
Button(action: delegate.captureZoom, label: {
Text("Zoom")
}).padding(5).buttonStyle(BorderlessButtonStyle());
})
.padding(5).buttonStyle(BorderlessButtonStyle());
Button(action: {
item.scale = 1.0
item.offset = CGPoint(x: 0,y: 0)
item.offset = CGPoint(x: 0, y: 0)
item.objectWillChange.send()
}, label: {
Text("Reset")
}).padding(5).buttonStyle(BorderlessButtonStyle());
Stepper(value:$item.rating, in: -1...5){
})
.padding(5).buttonStyle(BorderlessButtonStyle());
Stepper(value: $item.rating, in: -1...5) {
Text("*\(item.rating)").frame(width: 25)
}
Button(action: {
delegate.okEdit()
}, label: {
Text("ok")
}).padding(5).buttonStyle(BorderlessButtonStyle());Button(action: {
})
.padding(5).buttonStyle(BorderlessButtonStyle()); Button(action: {
delegate.cancelEdit()
}, label: {
Text("cancel")
}).padding(5).buttonStyle(BorderlessButtonStyle());
})
.padding(5).buttonStyle(BorderlessButtonStyle());
}
VStack {
KToggleButton(text: "snap", binding: $snap)
Button(action: {faceSelectedItem("sarah"); }, label: {Text("sarah")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("claudia"); }, label: {Text("claudia")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("jessica"); }, label: {Text("jessica")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("marleen"); }, label: {Text("marleen")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("renate"); }, label: {Text("renate")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("birgit"); }, label: {Text("birgit")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("barbara"); }, label: {Text("barbara")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("nina"); }, label: {Text("nina")}).buttonStyle(BorderlessButtonStyle())
Button(action: {faceSelectedItem("amruta"); }, label: {Text("amruta")}).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("sarah"); }, label: { Text("sarah") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("claudia"); }, label: { Text("claudia") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("jessica"); }, label: { Text("jessica") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("marleen"); }, label: { Text("marleen") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("renate"); }, label: { Text("renate") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("birgit"); }, label: { Text("birgit") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("barbara"); }, label: { Text("barbara") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("nina"); }, label: { Text("nina") }).buttonStyle(BorderlessButtonStyle())
Button(action: { faceSelectedItem("amruta"); }, label: { Text("amruta") }).buttonStyle(BorderlessButtonStyle())
}
TagEditor(item: item)
}.background(Color.clear)
}.background(Color.clear)
}
.background(Color.clear)
}
.background(Color.clear)
}
.onAppear {
UITableView.appearance().backgroundColor = .clear
@ -162,36 +198,185 @@ struct EditItemView: View {
UITableView.appearance().backgroundColor = .systemBackground
}
.frame(height: 800, alignment: .top)
.sheet(isPresented: $showProcessedImage) {
NavigationView {
VStack {
if let image = loadedImage {
GeometryReader { geometry in
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width, height: geometry.size.height)
.scaleEffect(imageScale)
.offset(imageOffset)
.gesture(
SimultaneousGesture(
MagnificationGesture()
.onChanged { value in
let delta = value / lastScale
lastScale = value
let newScale = imageScale * delta
imageScale = min(max(newScale, 1.0), 5.0)
}
.onEnded { value in
lastScale = 1.0
},
DragGesture(minimumDistance: 0)
.onChanged { value in
imageOffset = CGSize(
width: lastOffset.width + value.translation.width,
height: lastOffset.height + value.translation.height
)
}
.onEnded { value in
lastOffset = imageOffset
}
)
)
.onTapGesture(count: 2) {
// Double tap to reset zoom
withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
imageScale = 1.0
lastScale = 1.0
imageOffset = .zero
lastOffset = .zero
}
}
}
} else if let error = imageLoadError {
VStack(spacing: 20) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 60))
.foregroundColor(.orange)
Text("Failed to load image")
.font(.headline)
Text(error)
.font(.caption)
.foregroundColor(.secondary)
if let imageURL = processedImageURL {
Text("URL: \(imageURL)")
.font(.caption2)
.foregroundColor(.secondary)
}
}
.padding()
} else {
ProgressView("Loading image...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.navigationTitle("Processed Image")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
if loadedImage != nil && imageScale != 1.0 {
Button("Reset") {
withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
imageScale = 1.0
lastScale = 1.0
imageOffset = .zero
lastOffset = .zero
}
}
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("Done") {
showProcessedImage = false
loadedImage = nil
imageLoadError = nil
// Reset zoom state
imageScale = 1.0
lastScale = 1.0
imageOffset = .zero
lastOffset = .zero
}
}
}
.task {
if let imageURL = processedImageURL {
await loadImageFromURL(imageURL)
}
}
}
}
//Spacer()
}
func loadImageFromURL(_ urlString: String) async {
guard let url = URL(string: urlString) else {
imageLoadError = "Invalid URL"
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let image = UIImage(data: data) {
await MainActor.run {
loadedImage = image
imageLoadError = nil
}
} else {
await MainActor.run {
imageLoadError = "Failed to create image from data"
}
}
} catch {
await MainActor.run {
imageLoadError = "Failed to load image: \(error.localizedDescription)"
}
}
}
func faceSelectedItem(_ name: String) {
let path = item.fullPath.replacing("/srv/samba/ren", with: "z:")
let outpath1 = path.replacing("/", with: "")
let outpath = outpath1.replacing("z:", with: "z:/cut/videos/"+name+"/")
let outpath = outpath1.replacing("z:", with: "z:/cut/videos/" + name + "/")
print(path)
print(outpath1)
print(outpath)
Task {
isProcessing = true
processedImageURL = nil
if (snap) {
let imagePath = item.imageUrlAbsolute.replacing("http://linkstation:8089/ren", with: "z:").replacing("_thumb", with: "")
print(imagePath)
print(item.thumbUrlAbsolute)
let outimagepath = "z:/cut/snapshots/" + name + "/" + imagePath.substringStartingFrom(2).replacing("/", with: "")
try await FaceManager.sharedInstance.processImage(inputImagePath: imagePath, sourceFacePath: "benchmark/"+name+".jpg", outputPath: outimagepath)
do {
let response = try await FaceManager.sharedInstance.processImage(inputImagePath: imagePath, sourceFacePath: "benchmark/" + name + ".jpg", outputPath: outimagepath)
}
else {
try await FaceManager.sharedInstance.processVideo(inputVideoPath: path, sourceFacePath: "benchmark/"+name+".jpg", outputPath: outpath)
//try! await FaceManager.sharedInstance.processImage(inputImagePath: "input", sourceFacePath: "benchmark/Renate.jpg")
delegate.cancelEdit()
//if response.success, let outputPath = response.outputPath {
// Convert Windows path back to HTTP URL
let httpURL = outimagepath.replacing("z:", with: "http://linkstation:8089/ren").replacing("\\", with: "/")
processedImageURL = httpURL
print("Processed image URL: \(httpURL)")
// Show the sheet with the processed image
showProcessedImage = true
isProcessing = false
} catch {
print("Error processing image: \(error)")
isProcessing = false
}
} else {
do {
try await FaceManager.sharedInstance.processVideo(inputVideoPath: path, sourceFacePath: "benchmark/" + name + ".jpg", outputPath: outpath)
delegate.cancelEdit()
isProcessing = false
} catch {
print("Error processing video: \(error)")
isProcessing = false
}
}
}

Loading…
Cancel
Save