When I convert an image from PIL to OpenCV, colors change slightly.
from PIL import Image
import cv2
import numpy as np
image = cv2.imread('1.jpg')
image1=Image.open('1.jpg')
image1 = cv2.cvtColor(np.array(image1), cv2.COLOR_RGB2BGR)
print(image[79])
print(image1[79])
The first four rows are:
[144 151 148]
[101 108 105]
[121 128 125]
[108 118 112]
and
[140 152 146]
[ 97 109 103]
[117 129 123]
[104 118 112]
I thought the indexing may be off by one but it isn't. Is there a way to fix this?
This is the image (but it's the same on others too):
That suggests PIL and OpenCV are using different versions of libjpeg or using it with different parameters. Also it seems OpenCV tries to use libjpeg-turbo if you don't ask it not to do so, see the code here: https://github.com/opencv/opencv/blob/master/cmake/OpenCVFindLibsGrfmt.cmake#L39
This behaviour is dependent on different incompatible versions of libjpeg used by cv2 and PIL/Pillow, as #fireant already pointed out.
For example, when I try to run this code with older versions of Pillow (like 3.4.2), it generates same output. In my tests, Pillow 3.4.2 and older (oldest version tried was 2.2.0) all use libjpeg 8, while Pillow 4.0.0 and newer use libjpeg 9.2.
OpenCV, on the other hand, might use different versions on different systems:
On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default.
On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, "libjpeg-dev", in Debian* and Ubuntu*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.
So on Debian/Ubuntu systems opencv might use libjpeg-turbo which comes with the OS. (My machine, specifically, had version 8 installed.)
The way to fix this is to ensure that both Pillow and OpenCV use same libjpeg version.
You could try this:
if you have relatively new PIL/Pillow, downgrade it to version <= 3.4.2 (this is what worked for me)
pip install Pillow==3.4.2
if you have old Pillow version, you could try to upgrade it to version >= 4.0.0
If that doesn't help, your solution could be either of two:
recompiling your OpenCV with same libjpeg flavor as used by Pillow.
reinstalling Pillow from source using same libjpeg version as used by OpenCV.
libjpeg version may by different
Convert the original .jpg image to .bmp image
ffmpeg -i 1.jpg 1.bmp
than the opencv output and PIL output will be the same
Since OpenCV reads the image in as BGR format with cv2.imread() we need to convert it back to RGB before giving it to PIL.
Here is an example of reading an image with OpenCv and without change saving it with PIL:
image = cv2.imread('test.jpg')
pil_img = PIL.Image.fromarray(image)
pil_img.save('pil_img.jpg', 'JPEG')
The 'test.jpg' Image:
enter image description here
The 'pil_img.jpg' Image:
enter image description here
To correct this we need to use cv2.cvtColor to change the image to RGB
correct_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
pil_img = PIL.Image.fromarray(correct_img)
pil_img.save('pil_correct_img.jpg', 'JPEG')
Result: enter image description here
Related
I'm trying to use opencv-python with GPU on windows 10.
I installed opencv-contrib-python using pip and it's v4.4.0.42, I also have Cuda on my computer and in path.
Anyway, here is a (simple) code that I'm trying to compile:
import cvlib as cv
from cvlib.object_detection import draw_bbox
bbox, label, conf = cv.detect_common_objects(img,confidence=0.5,model='yolov3-worker',enable_gpu=True)
output_image = draw_bbox(img, bbox, label, conf)
First, here is the line that tell me that tf is ok with cuda:
2020-08-26 5:51:55.718555: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library cudart64_101.dll
but when I try to use my GPU to analyse the image, here is what happen:
[ WARN:0] global C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-j8nxabm_\opencv\modules\dnn\src\dnn.cpp (1429) cv::dnn::dnn4_v20200609::Net::Impl::setUpNet DNN module was not built with CUDA backend; switching to CPU
Is there a way to solve this without install opencv using cmake? It's a mess on windows...
The problem here is that version of opencv distributed with your system (Windows in this case) was not compiled with Cuda support. Therefore, you cannot use any cuda related function with this build.
If you want to have an opencv with cuda support, you will have to either compile it yourself (which may be tedious on windows) or find a prebuilt one somewhere. In case you want to go for the 1st solution, here is a link that may help you with the process: https://programming.vip/docs/compile-opencv-with-cuda-support-on-windows-10.html. Keep in mind that this will require you to install a bunch of SDK in the process.
Things seem to have changed a little since this question was asked initially:
From https://github.com/opencv/opencv-python
Option 1 - Main modules package: pip install opencv-python
Option 2 - Full package (contains both main modules and contrib/extra modules): pip install opencv-contrib-python (check contrib/extra modules listing from OpenCV documentation) ==> https://docs.opencv.org/master/
Sadly, not all of the modules listed above seem to be available in the "Full package" eg. cudafilters. If anyone knows any better, I for one would be very grateful to learn more.
For those who can get the same issue. As Harry mentionned, it's not possible to use GPU with opencv from pip, you have to "manually" build it using Cmake (for windows).
It's a bit tricky but there are many tutorials which are here to help you.
I spent two days trying to make cvlib works and that's why: one of the cudnn.dll curently available from Nvidia website is named:
Cudnn64_8.dll
and opencv (or tensorflow to be more precise) needs
Cudnn64_7.dll
in fact you just have to replace the 8 by the 7 ! ;)
That was the only hard part and I believed it came from the cmake process.
Thanks again Harry.
W10, Python 3.6, OpenCV 4.3.0, Spyder 4.0.1
I'm using the code from this post to take snap shots from my Intel(R) Realsense(TM) 3D Camera (Front F200).
The problem is that it is defaulting to Depth mode and not RGB.
Is there a way of switching between the two modes from my code?
I am trying to build an Image classifier with keras and tensorflow. However currently flow_from_directory does not see my images due to them being in .gif format (I checked this with .jpg and it works here). How can I fix this?
This old github page claims that I should be able to put .gif on my white_list_formats in the keras/preprocessing/image.py file. But after opening it there seems to be no white_list_formats in my version of image.py. Did keras change anything here?
I'm on Windows using anaconda3 distribution in case that matters.
Thanks for your help!
The github post you are referring to was posted for keras version 1.1.0. In the latest version they have removed that variable.
In the latest version of Keras, below formats are only supported.
PNG, JPG, BMP, PPM, TIF
Please refer to the this for documentation.
If you still want to try and edit white_list_format, please install keras 1.1.0 and try it.
It's possible that my problem is simply a Python 3 OpenCV bug, but I don't know. I have 32 bit Python version 3.4.3 installed in Windows 10. I have OpenCV 3.0.0 32 bit installed from this website http://www.lfd.uci.edu/~gohlke/pythonlibs/ (opencv_python‑3.0.0‑cp34‑none‑win32.whl).
I also have numpy 1.10.0b1 beta installed from that site.
I've tested out the same basic program flow below using OpenCV with Java and it works. For that reason I figure this may just be a Python bug issue. What happens is that the call to drawContours in the code below produces this error:
OpenCV Error: Image step is wrong (Step must be a multiple of esz1) in cv::setSize, file ......\opencv-3.0.0\modules\core\src\matrix.cpp, line 300
The test image I am using is 1168 x 1400 pixels.
Here is the code:
import cv2
import numpy as np
img = cv2.imread('test.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, threshImg = cv2.threshold(imgray,127, 255,cv2.THRESH_BINARY)
can = cv2.Canny(threshImg,100,200)
contImg, contours, hierarchy = cv2.findContours(can,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours,-1,(0,255,0))
cv2.imwrite('test write.jpg', img)
*******EDIT********
**I just solved the problem by installing numpy version 1.9.2 instead of the 1.10 beta.****
This has to do with development and beta releases of NumPy using relaxed strides. This is done to force detection of subtle bugs in third party libraries that make unnecessary assumptions about the strides of arrays.
Thanks to that the issue was detected a while back and is now fixed in the development version of OpenCV, see the relevant PR, but it will likely take some time until it makes it to a proper OpenCV release.
Regardless of that being fixed, as soon as the final version of NumPy 1.10 is released, you should be able to safely switch to it, even with the buggy current OpenCV version, as relaxed strides will be deactivated.
I solved the issue by installing numpy 1.9.2 instead of the new 1.10 beta version.
I'm trying to run this OpenCV tutorial with Python and OpenCV 2.4 but it gives me the following error :
OpenCV Error: Unsupported format or combination of formats (Both matrices must be floating-point (single or double precision)) in cvConvertPointsHomogeneous, file ........\opencv\modules\calib3d\src\fundam.cpp, line 901
How can I address this error?
I solved the problem by using OpenCV 3.0.0 rc-1 instead of 2.4
sift = cv2.SIFT() has to be replaced by sift = cv2.xfeatures2d.SIFT_create() for compatibility with this version.