How to set up opencv4 with python bindings and a GUI

I understand that python’s opencv bindings come from an opencv package compiled with enablePython set to my python package:

By default it is not compiled with any GUI:

>>> cv2.imshow("my window",img)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
cv2.error: OpenCV(4.3.0) /build/source/modules/highgui/src/window.cpp:651: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'

When I try to define it in one and only place I set up my python and opencv, it rebuilds my shell but fails to provide opencv bidings. My python shell nix file imported to my configuration.nix:

{ config, pkgs, ... }:
let
  python3-with-my-packages =
    pkgs.python3.withPackages (python-packages: with python-packages; [
      opencv4.override { enableGtk2 = pkgs.gnome2.gtk2; }
    ]);
in
{
  environment.systemPackages = with pkgs; [
    python3-with-my-packages
  ];
}

and sadly

>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'cv2'

Two question:

  1. Where the variables which can be overridden are documented? Is combing through github the only way to find out configuration options of a package?
  2. How do I get opencv to show a graphical window?

Thanks!

As a workaround for hacking it work I see that opencv can be installed in a conda environment conda-shell But this is sub optimal

Still it would be much better to know how to pass override options to another package installation to get opencv directly in project.

on nixos 20.09

would this work for you?


(Updated)

  • I haven’t looked correctly at the source code, sorry.
with import <nixpkgs> {};
(
let
  python = let
    packageOverrides = self: super: {
       opencv4 = super.opencv4.override  { 
        enableGtk2 = true; # boolean
        gtk2 = pkgs.gnome2.gtk; # pkgs.gtk2-x11
        };
      #opencv4_ = super.opencv4.overrideAttrs (old: rec { 
      #  gtk2 = pkgs.gtk2 ; # pkgs.gtk2-x11 # pkgs.gnome2.gtk;
      #  # doCheck = false;
      #  });
    };
  in 
  pkgs.python3.override {inherit packageOverrides; self = python;};
in 
python.withPackages(ps: with ps; [
    opencv4 
    ])
).env

  • parameter are “documented” in source code
  • pkgs.gtk2-x11 sounds like it could be helpful (for anything tkinter related use pkgs.python38Full)

nixpkgs-channels is DEPRECATED
use nixpkgs

1 Like

Thanks @igel , that may work. I’m a bit lost with the syntax though - I normally only use nix for system wide configuration and what you posted is something to do with environment expression (?).

I read the manual and nix expression docs (as well as nix pills…) but still struggle a lot with our syntax…

how do I get from your snipped to a package declaration?

Here’s what I tried:

{ config, pkgs, ... }:
let python =
    let
    packageOverrides = self:
    super: {
      opencv4 = super.opencv4.overrideAttrs (old: rec {
        enableGtk2 = pkgs.gtk2 ; # pkgs.gtk2-x11 # pkgs.gnome2.gtk;
        # doCheck = false;
        });
    };
    in
      pkgs.python3.override {inherit packageOverrides; self = python;};
in
{
environment.systemPackages = with pkgs; [
  python.withPackages(ps: with ps; [
  opencv4
    ])
];
}

and it tells me that

The option value `environment.systemPackages.[definition 2-entry 1]' in `/etc/nixos/pythonix.nix' is not of type `package'.

which is fair enough, but I do not know what type it is… :wink:

Thanks for any directions.

What you have now:

environment.systemPackages = with pkgs; [
  # list item #1 (function type)
  python.withPackages
  # list item #2 (function type)
  (ps: with ps; [
  opencv4
  ])
];

What you need:

environment.systemPackages = with pkgs; [
  # list item #1 (package type)
  (python.withPackages (ps: with ps; [
    opencv4
  ]))
];
1 Like

Ah, thanks, I was close :slight_smile:

So it is building now, it attempts with gtk but it fails:

-- Checking for module 'gtk+-3.0'
--   No package 'gtk+-3.0' found
-- Checking for module 'gtk+-2.0'
--   No package 'gtk+-2.0' found

I also tried to activate ffmpeg, and it is the same story, it doesn’t seem to find the library during build process.

Any ideas? I wonder how is it possible that conda-shell manages to provide GUI so seamlessly, it must also use system library for display after all, right?

Now it works, thanks @jtojnar and @igel !

How did you make it work in the end ?

As per @igel solution. I’ve put this .env thing into conifguration file, as follows:

{ config, pkgs, ... }:
let python =
    let
    packageOverrides = self:
    super: {
      opencv4 = super.opencv4.override {
        enableGtk2 = true;
        gtk2 = pkgs.gtk2;
        #enableFfmpeg = true; #here is how to add ffmpeg and other compilation flags
        #ffmpeg_3 = pkgs.ffmpeg-full;
        };
    };
    in
      pkgs.python3.override {inherit packageOverrides; self = python;};
in
{
environment.systemPackages = with pkgs; [
  (python.withPackages(ps: with ps; [
    opencv4
  ]))
];
}

Hope that works for you @573 !

2 Likes

@mixmixmix this works! Thanks !

1 Like