1. AnimatedRotor
  2. Resolution 200.0
    1. 1.0
    2. 3.0
    3. 2.0
  3. Resolution 512.0
    1. 1.0
    2. 2.0
    3. 3.0
    4. 2.5
    5. 1.5

AnimatedRotor

Paints a series of images, each to match the content of one while in the style of another using:
  1. Random noise initialization
  2. Standard VGG19 layers
  3. Operators to match content and constrain and enhance style
  4. Progressive resolution increase
  5. Rotational symmerty constraint caused by a kaliedoscopic image layer
  6. A content seed image to guide the aspect ratio
The parameters for each frame are fixed, but due to the random initialization and loose constraints we can achive a dynamic effect.

Color Permutations:

  1. Order: 1
    • 1,2,3
  2. Order: 2
    • -1,-3,-2
    • -3,-2,-1
    • -2,-1,-3
    • -1,-2,-3
    • 1,-2,-3
    • 1,-3,-2
    • -1,2,-3
    • -3,2,-1
    • 1,2,-3
    • 2,1,-3
    • -2,-1,3
    • -1,-2,3
    • 3,-2,1
    • 1,-2,3
    • -1,2,3
    • -1,3,2
    • 3,2,1
    • 1,3,2
    • 2,1,3
  3. Order: 3
    • -3,1,-2
    • -2,-3,1
    • -2,3,-1
    • 2,3,1
  4. Order: 4
    • -3,-2,1
    • -2,1,-3
    • -1,-3,2
    • 1,-3,2
    • -3,2,1
    • -2,1,3
  5. Order: 6
    • -2,-3,-1
    • 2,-3,1
    • -3,1,2
    • -2,3,1

Tiling Aspect Ratios:

  1. Triangular or Hexagonal: 1.732 or 0.5774
  2. Square: 1.0

Subreport: AnimatedRotor_0901677c-8f71-48ab-8ff9-1ac679ab5cb3_log_com.simiacryptus.ref.lang.ReferenceCountingBase

Code from AnimatedRotor.scala:71 executed in 0.00 seconds (0.000 gc):

    () => {
      implicit val implicitLog = log
      // First, basic configuration so we publish to our s3 site
      log.setArchiveHome(URI.create(s"s3://$s3bucket/$className/${log.getId}/"))
      log.onComplete(() => upload(log): Unit)
      ImageArtUtil.loadImages(log, styleUrl, (maxResolution * Math.sqrt(magnification)).toInt).foreach(x => log.p(log.jpg(x, "Input Style")))
      log.p(log.jpg(ImageArtUtil.loadImage(log, contentUrl, maxResolution), "Input Content"))
  
      def frames = keyframes * 2 - 1
  
      val canvases = (1 to frames).map(_ => new RefAtomicReference[Tensor](null)).toList.toBuffer
      // Execute the main process while registered with the site index
      val registration = registerWithIndexGIF_Cyclic(canvases.map(_.get())
        .filter(_ != null)
        .map(t => {
          val kaleidoscope = getKaleidoscope(t.getDimensions)
          val result = kaleidoscope.eval(t)
          kaleidoscope.freeRef()
          val tensorList = result.getData
          val transformed = tensorList.get(0)
          result.freeRef()
          transformed
        }))
      try {
        animate(
          contentUrl = contentUrl,
          initUrl = initUrl,
          canvases = canvases,
          networks = (1 to frames).map(f => f.toDouble -> {
            new VisualStyleNetwork(
              styleLayers = List(
                // We select all the lower-level layers to achieve a good balance between speed and accuracy.
                VGG19.VGG19_1a,
                VGG19.VGG19_1b1,
                VGG19.VGG19_1b2,
                VGG19.VGG19_1c1,
                VGG19.VGG19_1c2,
                VGG19.VGG19_1c3,
                VGG19.VGG19_1c4,
                VGG19.VGG19_1d1,
                VGG19.VGG19_1d2,
                VGG19.VGG19_1d3,
                VGG19.VGG19_1d4
              ),
              styleModifiers = List(
                // These two operators are a good combination for a vivid yet accurate style
                new GramMatrixEnhancer(),
                new MomentMatcher()
              ),
              styleUrls = Option(styleUrl),
              magnification = magnification,
              // Our optimization network should be built with a kaliedoscope appended to the canvas
              viewLayer = dims => getKaleidoscope(dims.toArray)
            )
          }).toList.toBuffer,
          optimizer = new BasicOptimizer {
            override val trainingMinutes: Int = 60
            override val trainingIterations: Int = 10
            override val maxRate = 1e9
  
            // The canvas result should be processed by the kaliedoscope
            override def renderingNetwork(dims: Seq[Int]) = getKaleidoscope(dims.toArray)
  
            // By default, we use a trust region that constrains the canvas pixel values from 0-256.
            // This conflicts with using a kaliedoscope, whose output is bounded and input may be out of that range.
            override def trustRegion(layer: Layer): TrustRegion = null
          },
          resolutions = new GeometricSequence {
            override val min: Double = minResolution
            override val max: Double = maxResolution
            override val steps = AnimatedRotor.this.steps
          }.toStream.map(_.round.toDouble),
          renderingFn = (dims: Seq[Int]) => getKaleidoscope(dims.toArray))
        null
      } finally {
        registration.foreach(_.stop()(s3client, ec2client))
      }
    }

Returns:

    <function0>

Input Style

Input Style

Input Content

Resolution 200.0

1.0

Subreport: Optimization

3.0

Subreport: Optimization

2.0

Subreport: Optimization

Resolution 512.0

1.0

Subreport: Optimization

2.0

Subreport: Optimization

3.0

Subreport: Optimization

2.5

Subreport: Optimization

1.5

Subreport: Optimization