Skip to content

Commit

Permalink
Additional content aggregation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
lucaro committed Dec 23, 2023
1 parent e59760e commit 47e8d26
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.vitrivr.engine.index.aggregators

import org.vitrivr.engine.core.context.IndexContext
import org.vitrivr.engine.core.model.content.element.AudioContent
import org.vitrivr.engine.core.model.content.element.ContentElement
import org.vitrivr.engine.core.model.content.element.ImageContent
import org.vitrivr.engine.core.model.content.element.TextContent
import org.vitrivr.engine.core.model.retrievable.Retrievable
import org.vitrivr.engine.core.operators.Operator
import org.vitrivr.engine.core.operators.ingest.Aggregator
import org.vitrivr.engine.core.operators.ingest.AggregatorFactory
import org.vitrivr.engine.core.operators.ingest.Segmenter

/**
* A [Aggregator] that returns the middle [ContentElement] of each type.
*
* @version 1.0.0
*/
class CenterContentAggregator : AggregatorFactory {

/**
* Returns an [CenterContentAggregator.Instance].
*
* @param input The [Segmenter] to use as input.
* @param context The [IndexContext] to use.
* @param parameters Optional set of parameters.
* @return [AllContentAggregator.Instance]
*/
override fun newOperator(input: Segmenter, context: IndexContext, parameters: Map<String, String>): Aggregator = Instance(input, context)

/**
* The [Instance] returns by the [AggregatorFactory]
*/
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) : AbstractAggregator(input, context) {
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> {
val imageContent = content.filterIsInstance<ImageContent>()
val audioContent = content.filterIsInstance<AudioContent>()
val textContent = content.filterIsInstance<TextContent>()
return listOfNotNull(
imageContent.let { if (it.isNotEmpty()) it[it.size / 2] else null },
audioContent.let { if (it.isNotEmpty()) it[it.size / 2] else null },
textContent.let { if (it.isNotEmpty()) it[it.size / 2] else null }
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.vitrivr.engine.index.aggregators.image

import org.vitrivr.engine.core.context.IndexContext
import org.vitrivr.engine.core.model.color.MutableRGBFloatColorContainer
import org.vitrivr.engine.core.model.color.RGBByteColorContainer
import org.vitrivr.engine.core.model.content.element.ContentElement
import org.vitrivr.engine.core.model.content.element.ImageContent
import org.vitrivr.engine.core.model.retrievable.Retrievable
import org.vitrivr.engine.core.operators.Operator
import org.vitrivr.engine.core.operators.ingest.Aggregator
import org.vitrivr.engine.core.operators.ingest.AggregatorFactory
import org.vitrivr.engine.core.operators.ingest.Segmenter
import org.vitrivr.engine.core.util.extension.getRGBArray
import org.vitrivr.engine.index.aggregators.AbstractAggregator

/**
Expand All @@ -27,18 +30,52 @@ class RepresentativeImageContentAggregator : AggregatorFactory {
* @param parameters Optional set of parameters.
* @return [RepresentativeImageContentAggregator.Instance]
*/
override fun newOperator(input: Segmenter, context: IndexContext, parameters: Map<String, String>): Aggregator = Instance(input, context)
override fun newOperator(input: Segmenter, context: IndexContext, parameters: Map<String, String>): Aggregator =
Instance(input, context)

/**
* The [Instance] returns by the [AggregatorFactory]
*/
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) : AbstractAggregator(input, context) {
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) :
AbstractAggregator(input, context) {
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> {
val images = content.filterIsInstance<ImageContent>()
if (images.isEmpty()) {
return emptyList()
}
TODO()

if (images.size == 1) {
return images
}

/* Compute average image. */
val firstImage = images.first()
val height = firstImage.height
val width = firstImage.width
val colors = List(firstImage.width * firstImage.height) { MutableRGBFloatColorContainer() }
images.forEach { imageContent ->
require(imageContent.height == height && imageContent.width == width) { "Unable to aggregate images! All images must have same dimension." }
imageContent.content.getRGBArray().forEachIndexed { index, color ->
colors[index] += RGBByteColorContainer.fromRGB(color)
}
}

/* normalize */
val div = images.size.toFloat()
colors.forEach { it /= div }

/* find image with smallest pixel-wise distance */
val mostRepresentative = images.minBy { imageContent ->

imageContent.content.getRGBArray().mapIndexed { index, color ->
RGBByteColorContainer.fromRGB(color).toFloatContainer().distanceTo(colors[index])
}.sum()

}

return listOf(mostRepresentative)


}
}
}

0 comments on commit 47e8d26

Please sign in to comment.