Narážím na velmi nepříjemný problém v provedení jednoduchý rám v průměru postupu s Core Image. Stručně řečeno, jsem se urvat snímky z videa vyrovnávací paměti v zachycení výstupní metody:
func captureOutput(_ output: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
guard let cvBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
let newImage = CIImage(cvImageBuffer: cvBuffer)
...
// Frame averaging part using a CIImageAccumulator
if (slowIncrement == 0.0) {
accumulator?.setImage(newImage)
} else {
makeAverageFiler.currentStack = accumulator?.image()
makeAverageFiler.newImage = newImage
makeAverageFiler.count = slowIncrement
guard let processedImage = makeAverageFiler.outputImage else {return}
accumulator?.setImage(processedImage)
}
slowIncrement += 1.0
...
}
Udělal jsem vlastní filtr s následující jádra:
float4 makeAverage(sample_t currentStack, sample_t newImage, float stackCount) {
float4 cstack = unpremultiply(currentStack);
float4 nim = unpremultiply(newImage);
float4 avg = ((cstack * stackCount) + nim) / (stackCount + 1.0);
return premultiply(avg);
}
Algoritmus by měl být správný. Když jsem test stejné s malým python fragment kódu na video snímků, funguje to perfektně. V app funguje také bod. Nicméně, když aplikace získává více a více snímků, vidím, že barvy se pomíchaly a divné barevné skvrny se začnou objevovat. Mám podezření, že základní obraz není provádění výpočtů na barevné kanály správně, nějak barevné kanály sejmou.
To je, jak jsem inicializován CIImageAccumulator:
let accumulator = CIImageAccumulator(extent: CGRect(x: 0, y: 0, width: 3024, height: 4032), format: .RGBAf)
Musím použít akumulátor, jinak, využití paměti roste na dobu neurčitou a aplikace přestane pracovat.
Vidím, že změna formátu má vliv na výsledky. Nicméně, nemohl jsem najít vhodný formát, který by tento problém zmizet.
Co dělám špatně? Na cvImageBuffer má 32 bit-per-pixel ARGB formát pixelu. Je jádro, obrazové jádro provádějící konverzi na 128 bit-per-pixel automaticky?
Další věcí, které jsem zkoušel:
- unmultiply a premultiply nezdá opravit výsledky
- změna workingformat z CIContext také nezdá do práce. Zejména, zdá se, že jsem se může nastavit pouze v sRGB formátu jako pracovní CIContextOption. Jiné formáty následek zvýšení výjimku.
Já bych opravdu rád, aby se zabránilo používání kovových vlastní shadery a držet core image. Díky předem za vaši pomoc!
Aktualizace
Zde je příklad podivné skvrny, které se začnou objevovat po získání chvíli. V tomto případě jsem jen pohybem telefonu kolem, zatímco zachycení. V reálném světě použití, tento problém se zdá být silně při získávání pomalu se pohybující mraky.
Aktualizace 2
Prohlašuji CIContext jako vlastnost view controller. Pak jsem ji inicializovat v viewDidLoad takto:
ciContext = CIContext(mtlDevice: metalView.metalDevice, options: [.workingFormat : CIFormat.RGBAf,
.workingColorSpace: NSNull(),
.cacheIntermediates : false,
.highQualityDownsample: true])
Používám ciContext v několika místech, jak vykreslit CIImages na tažná, vytvořit přechodné CGImages a také uložit obrázky ve formátu Jpeg. Například, tady je render použití:
self.ciContext.render(centeredImage,
to: currentDrawable.texture,
commandBuffer: commandBuffer,
bounds: CGRect(origin: .zero, size: view.drawableSize),
colorSpace: CGColorSpaceCreateDeviceRGB())