cocoa-xu / evision

Evision: An OpenCV-Erlang/Elixir binding
https://evision.app
Apache License 2.0
322 stars 22 forks source link

Inheritance with Evision.Features2D #223

Closed gworkman closed 4 months ago

gworkman commented 7 months ago

Hello!

I'm trying to reproduce in Elixir some of the lower-level stitching pipeline from python stitching package. Kudos to the team over there, they have made it really clear what is going on under the hood, but in my efforts I can't seem to find a way to Evision to work with applying some of the higher-level abstractions to specific instances of detectors, matchers, etc.

Specifically, here's the first file I started to port to Elixir:

defmodule FeatureDetector do
  alias Evision, as: CV

  def get_detector(type, opts \\ [nfeatures: 500])
  def get_detector(:orb, opts), do: CV.ORB.create(opts)
  def get_detector(:sift, opts), do: CV.SIFT.create(opts)
  def get_detector(:akaze, opts), do: CV.AKAZE.create(opts)
  def get_detector(:brisk, opts), do: CV.BRISK.create(opts)

  # this does not work
  # no function clause matching in Evision.Detail.computeImageFeatures2/2
  # expects a struct %Evision.Feature2D{}
  def detect(detector, image) do
    Evision.Detail.computeImageFeatures2(detector, image)
  end

  # this works, but returns {[keypoints], [descriptors]}
  # I need %Evision.Detail.ImageFeature{} at a later step in the pipeline
  def detect(detector, image) do
    keypoints = detector.__struct__.detect(detector, image)
    detector.__struct__.compute(detector, image, keypoints)
  end

  def draw_keypoints({keypoints, _descriptors}, image) do
    CV.drawKeypoints(image, keypoints, image)
  end
end

However, the call to Evision.Detail.computeImageFeatures2(detector, image) does not work. The error message is:

** (FunctionClauseError) no function clause matching in Evision.Detail.computeImageFeatures2/2    

    The following arguments were given to Evision.Detail.computeImageFeatures2/2:

        # 1
        %Evision.ORB{ref: #Reference<0.2859087556.23461901.194184>}

        # 2
        %Evision.Mat{
          channels: 1,
          dims: 2,
          type: {:u, 8},
          raw_type: 0,
          shape: {400, 400},
          ref: #Reference<0.2859087556.23461914.203962>
        }

    Attempted function clauses (showing 1 out of 1):

        def computeImageFeatures2(featuresFinder, image) when is_struct(featuresFinder, Evision.Feature2D) and (is_struct(image, Evision.Mat) or is_struct(image, Nx.Tensor))

    (evision 0.1.34) lib/generated/evision_detail.ex:190: Evision.Detail.computeImageFeatures2/2

I haven't found a way to convert the instance of the feature finder (in this case, Evision.ORB) to the base Feature2D struct - I tried copying the ref from the ORB struct to a new Feature2D struct, but it didn't work. How should I proceed?

Thanks!

cocoa-xu commented 4 months ago

Hi @gworkman, thanks for reporting this issue, and sorry that I didn't have enough bandwidth to look into this problem for a long time. This issue is fixed in #231, and it will be released with v0.1.36 at sometime later this week. I'll let you know once v0.1.36 is shipped!

gworkman commented 4 months ago

Thanks! Looking forward to it. I'll test it out this week and report if any other issues pop up with regards to creating a customized image stitching pipeline (this is perfect timing as I'm just now looking into this again!).

cocoa-xu commented 4 months ago

Hi @gworkman, v0.1.36 is released, and it works now. :)

iex> image = Evision.imread("test.jpg")
%Evision.Mat{
  channels: 3,
  dims: 2,
  type: {:u, 8},
  raw_type: 16,
  shape: {1080, 1920, 3},
  ref: #Reference<0.1560746059.813301793.233425>
}
iex> opts = [nfeatures: 500]
[nfeatures: 500]
iex> detector = Evision.ORB.create(opts)
%Evision.ORB{ref: #Reference<0.1560746059.813301784.233032>}
iex> Evision.Detail.computeImageFeatures2(detector, image)
%Evision.Detail.ImageFeatures{ref: #Reference<0.1560746059.813301784.233033>}