Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bitmapOffset - run only inside a given bitmap region #19

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

cancerberoSgx
Copy link
Collaborator

@cancerberoSgx cancerberoSgx commented Jul 12, 2019

This PR is not meant at all to be merged but as a starting point to discuss this feature. Also kind of personal notes and updates on these research.

What

Visually this will enable the users to select a region of the bitmap and apply the algorithm only there with custom options. In my experience I've noticed that some shape combinations will ignore some areas (often faces). Also could help with lines/curves that often are "too long" and ruin a landscape

Internally it isolates the region at the bitmap level so the whole algorithm runs in that context (reads, creates, mutates and render shapes only there). algorithm in new regions consume existing bitmap and collaborate with future sections/series.

Changes

  • Bitmap now supports the concept of offset (an internal rectangle inside).
    • By default is not enabled so it behaves just like now.
    • when set, some Bitmap members change the behavior (width, height, getPixel and setPixel )
      and interpret coordinates as relative to the offset.
    • Can be set dynamically and don't clone or destroy any bitmap or model (reuse existing ones), just some numbers in Bitmap that represent the offset.
    • I put all offset-related logic in a separated base class from which Bitmap inerith so its only responsibilty keeps being buffer/bytes/colors/render
    • setOffset is a method in the runner and not an option. when set it modifies runner's model and bitmaps. If can be called at any time in between steps. I needed to create setOffset method in runner, bitmap and model I thought it have more sense as a runner method, but it couldbe also implemented as an option to have them all in the same place.
    • updates runner's model's score. (same code as in the constructor) If I don't do it, I get errors FAIL: Math.isFinite(result)' on differencePartial(). I think updating the score solves the issue but I really don't know the impact or if it can be done better
    • At the bitmap level it support offset save/restore since I needed this in Mode.new(). I will change that probably if we get rid of Bitmap.create and implement a similar smarter method - and probably also remove support for this "save/restore" feature.
    • (The worst part) For it to support SVG I needed to implement Shape.translate(). Probably this is not required and it can be improved and optimized. basically after the step finish, I need to translate the new shape by the current offset and I'm doing it between steps. Is not big deal since is only one and just sums, but another way of support this could be storing the current offset in the shapes so themselves are responsible of managing this/ supporting offset?). Nevertheless if a new shape doesn't implement this it will keep working (incorrectly if using offsets and SVG)
  • bitmap image output doesn't need this.

Concerns:

  • WIP - still testing.
  • performance impact: on set/getPixel since they need to support relative coordinates.
  • I added a lots of code risking the library simplicity, mostly Shape.translate() rthat probably is not needed- WiIll keep trying to solve the problem differently.
  • Nevertheless I though about it and didn't found a way of implementing this feature in an auxiliary library.I'm not sure if these kind of features can be done without these kind of bit refactors.
  • not sure the consequences of reseting the score in the model @Tw1ddle ?

Nice to have

non rectangular regions for shapes/faces - rectangles are too artificial and pronounced...

@cancerberoSgx
Copy link
Collaborator Author

cancerberoSgx commented Jul 12, 2019

some examples:


[
    {
    iterations: 255,
    shapeTypes: [ShapeTypes.ROTATED_ELLIPSE],
    alpha: 22,
    candidateShapesPerStep: 22,
    shapeMutationsPerStep: 44,
  }, 
  {
    iterations: 355,
    bitmapOffset: { x: 211, y: 11, width: 158, height: 188 },
    shapeTypes: [ShapeTypes.RECTANGLE],
    alpha: 141,
    shapeMutationsPerStep: 55,
    candidateShapesPerStep:70,
  }, 
  {
    iterations: 255,
    shapeTypes: [ShapeTypes.TRIANGLE],
    bitmapOffset: { x:  12, y: 11, width: 188, height: 138 },
    alpha: 152,
    shapeMutationsPerStep: 55,
    candidateShapesPerStep: 70,
  },
  {
    iterations: 755,
    shapeTypes: [ShapeTypes.LINE, ShapeTypes.QUADRATIC_BEZIER],
    bitmapOffset: { x:  32, y: 122, width: 218, height: 148 },
    shapeMutationsPerStep: 55,
    candidateShapesPerStep: 110,
    alpha: 166
  }
  ]

blubells 6


[
    {
    iterations: 55,
    shapeTypes: [ShapeTypes.ROTATED_ELLIPSE, ShapeTypes.TRIANGLE],
    alpha: 62,
    candidateShapesPerStep: 42,
    shapeMutationsPerStep: 44,
  }, 
  {
    iterations: 55,
    bitmapOffset: { x: 0, y: 0, width: 333, height: 220 },
    shapeTypes: [ShapeTypes.RECTANGLE],
  }, 
  {
    iterations: 55,
    shapeTypes: [ShapeTypes.TRIANGLE],
    bitmapOffset: { x:  444, y: 0, width: 311, height: 220 },
  },
  {
    iterations: 255,
    shapeTypes: [ShapeTypes.QUADRATIC_BEZIER],
    bitmapOffset: { x:  0, y: 300, width: 688, height: 200 },
    alpha: 196
  }
  ]

parrots 1

@Tw1ddle
Copy link
Owner

Tw1ddle commented Jul 12, 2019

Thanks for this.

This is a legit approach for restricting where the algorithm runs, though I think a more flexible way to solve the problem this addresses is to make it simple to override the setup/mutation functions for the shapes themselves. I've started to implement this in my C++ application as an "area of influence" shape/mask that limits where shapes can spawn/mutate, some Chaiscript scripts use this (I need to update the C++ app and make some videos about how to use it!).

Approaching it this way makes it easier to provide custom versions of the shape setup/mutation code as add-ons/extensions. That's sort of the idea I have for this C++ code anyway - to eventually have many different versions of scripts for setting up/mutating shapes. I don't suggest using scripts for the Haxe library, but maybe a new set of functions (which together provide a "mode" where the code only runs within a region), for example:

https://github.com/Tw1ddle/geometrize-scripts/tree/783e5c670d0aca2394d9a81308c7b77fa4fe39db/scripts/pointer_area_of_interest_mutators

https://github.com/Tw1ddle/geometrize-scripts/tree/783e5c670d0aca2394d9a81308c7b77fa4fe39db/scripts/default_shape_mutators

What do you think? I could do it like this for the Haxe library when I find some time.

@cancerberoSgx
Copy link
Collaborator Author

Aja I'm checking it out. Whatever you think is the better approach would be awesome to implement in this library too since this feature attacks a problem I think is inerenth to the algorithm: each shape has a "taste" for different image "patterns" and if for example, a region of the image has a pattern with rect lines or rect angles then rectangles and lines simply won't be drawn on other parts of the image without those patterns.

About your solution, I'm not sure only with custom Shape's methods for render and mutate will be enough for this library and I think we might still need to add some "offset" logic on the bitmap and model. In the meanwile I will continue working on some tests for performance to see the cost of the current code.

Thanks and feel free to close this PR if you think so we can still keep discussing the feature here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants