I was using OpenCV to read the images from a folder. A lot of messages like this show up:
Corrupt JPEG data: premature end of data segment
Premature end of JPEG file
Premature end of JPEG file
Premature end of JPEG file
How to catch this exception and remove these image files?
Since you said you are reading 'images' (multiple images), you would be looping through files in the folder that you are reading them from.
In that case, if you check if the image is valid or not by using the following :
Mat image;
image = imread(argv[1], CV_LOAD_IMAGE_COLOR); // Read the file
if(! image.data ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
return -1;
}
you can then proceed to deleting files which are corrupt/bad.
I've been struggling to find a solution too. Read tens of articles, most of which just state that openCV does not throw errors and only outputs the error on stderr.
Some suggest to use PIL, but that does not detect most of the image corruptions. Usually only premature end of file.
However the same errors that OpenCV warns about can be detected via imagemagick.
Install imagemagick (https://imagemagick.org/)
Make sure you have it in the path.
Put the following sub into your code and call it to verify a file from wherever you need to. It also outputs errors to stderr, however it raises an error (thanks to "-regard-warnings")
import subprocess
def checkFile(imageFile):
try:
subprocess.run(["identify", "-regard-warnings", imageFile]).check_returncode()
return true
except (subprocess.CalledProcessError) as e:
return false
If you don't want the check to spam your outputs, add stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL params to the run function call.
On windows if you have not installed the legacy commands use the new syntax:
subprocess.run(["magick", "identify", "-regard-warnings", imageFile]).check_returncode()
Related
Starting point:
There is video called myVideo.mp4 in a folder (/1_original_videos) in a Bucket called myBucket in Google Cloud Storage.
myBucket
-->/1_original_video
-->myVideo.mp4
Goal:
The goal is to take this video, split it into chunks in a Cloud Function myCloudFunction and save the chunks in a subfolder called chunks in myBucket. The part of dividing into chunks is not a problem. The problem is reading the video.
myCloudFunction must be triggered with an HTTP trigger.
_______________
myVideo.mp4 ---->|myCloudFunction|----> chunk0.mp4, chunk1.mp4, chunk2.mp4, ... , chunkN-1.mp4
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
^
|
|
|
HTTP trigger
If the video were on my local computer, in order to read it, the following would be enough:
import cv2
cap = cv2.VideoCapture("/some/path/in/my/local/computer/myVideo.mp4")
Attempts:
Path with authenticated URL:
import cv2
cap = cv2.VideoCapture("https://storage.cloud.google.com/myBucket/1_original_videos/myVideo.mp4")
When testing this approach, this is the resulting message (see complete code below):
"File Cannot be Opened"
Complete code:
import cv2
def video2chunks(request):
# Request:
REQUEST_JSON = request.get_json()
#If the HTTP contains a key called "start" (e.g. "{"start":"whatever"}"):
if REQUEST_JSON and 'start' in REQUEST_JSON:
try:
# Create VideoCapture object:
cap = cv2.VideoCapture("https://storage.cloud.google.com/myBucket/1_original_videos/myVideo.mp4")
# If no VideoCapture object is created:
if not cap.isOpened():
message = "File Cannot be Opened"
# If a Videocapture object is created, compute some of the video parameters:
else:
fps = int(cap.get(cv2.CAP_PROP_FPS))
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = int(cv2.VideoWriter_fourcc('X','V','I','D')) # XVID codecs
message = "Video downloaded successfully. Some params are: "
message += "FPS= " + str(fps) + " | size= " + str(size)
except Exception as e:
message = str(e)
else:
message = "You did not provide a key called start "
return message
I have been trying to find examples or a better way to do this in a Cloud Function but so far have been unsuccessful. Any alternatives would also be very much appreciated.
I'm not aware whether the cv2 library supports reading directly from Cloud Storage in some way. Nonetheless as Christoph points out you may download the file, process it and upload the results. The code will be essentially the same as running locally.
One thing to note is that Cloud Functions offer a temporal directory which is the way I chose to store the image. However it's important to know that any file stored there is actually consuming part of your function RAM, so the allocated function memory should be sized accordingly. Also you may notice the temp files are deleted before exiting the function, this is just a best practice in Cloud Functions.
import cv2
import os
from google.cloud import storage
def myfunc(request):
# Substitute the variables below for whatever suits your needs
# BUCKET_ID :: The bucket ID
# INPUT_IMAGE_GCS :: Path to GCS object
# OUTPUT_IMAGE_PATH :: Path to save the resulting image/video
# Read video and save to /tmp directory
bucket = storage.Client().bucket(BUCKET_ID)
blob = bucket.blob(INPUT_IMAGE_GCS)
blob.download_to_filename('/tmp/video.mp4')
# Video processing stuff
vidcap = cv2.VideoCapture('/tmp/video.mp4')
success, image = vidcap.read()
cv2.imwrite("/tmp/frame.jpg", image)
# Save results to GCS
img_blob = bucket.blob('potato/frame.jpg')
img_blob.upload_from_filename(OUTPUT_IMAGE_PATH)
# Delete tmp resources to free memory
os.remove('/tmp/video.mp4')
os.remove('/tmp/frame.jpg')
return '', 200
I'm using cmake to build my project with opencv. There are two sub-projects, A and B, under the top directory. A has no opencv function while B uses VideoCapture to get image from webcam. There is no problem at first.
However, after I add the code from B to A, B can still capture image from webcam, but A cannot do the same thing, the error is below:
HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV
VIDIOC_STREAMON: Inappropriate ioctl for device
It is strange, and I find that VideoCapture cannot get image in A, the code is below
VideoCapture cam;
cam.open(0);
if(!cam.isOpened()){
cout << "Failed to open webcam" << endl;
return false;
}
Mat Image;
cam >> Image;
if(Image.empty())
cout<<"Image empty"<<endl;
"Image empty" is always in console, which means it just cannot capture the image at all!!
I followed some suggestions such as install "v4l2ucp", but there is no folder under "/usr/lib/" named "libv4l", so LD_PRELOAD=/usr/lib/libv4l/v4l1compat.so dose not work.
I will very appreciate it if someone could give me some help to solve the problem in project A.
The file might not necessarily be there. Try find / -name "*v4l1compat.so*" 2>/dev/null or find / -name "*libv4l*" 2>/dev/null. It should succeed since your project B captures frames just fine. Then try to export found file to LD_PRELOAD.
If it won't succeed - check out your libv4l installation.
And make sure you trying to open() the correct camera which is not already in use.
In opencv 2.4.6. I am trying to load a mat image file with a simple code given below. But the image is not loaded as I print the image size, it is showing '0'. Can anybody please tell me , what is going wrong?
int main(int argc, char argv[])
{
Mat a=imread("C:/image3.jpg");
cv::Size frame11_size = a.size();
printf("%d",frame11_size.height);
return 0;
}
Update: I solved the problem. The problem was, I was only including all the library,include and additional dependencies in 'debug mode' only. I did not change anything in 'release mode'. When I change the properties in 'release mode' as-well, it worked. thanks all for your kind responses, I am giving '+1' for your answers.
I think there should be single slash on your image path, and always check whether image is successfully loaded.
Mat a=imread("C:/image3.jpg");
if(! a.data ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
return -1;
}
OpenCV can't open jpg files by itself. It depends on third parties to do so. Maybe you are missing certain dlls, or maybe your OpenCV installation don't have the right path to them. To test this assumption store your image in other formats. For example pgm or ppm. Those formats does not perform any encoding and just store image buffer in file as is. As a result OpenCV will not need any external libraries to open image in ppm format.
I use puthon 2.7, windows 7 and opencv 2.4.6. and I try to run the following code:
https://github.com/kyatou/python-opencv_tutorial/blob/master/08_image_encode_decode.py
#import opencv library
import cv2
import sys
import numpy
argvs=sys.argv
if (len(argvs) != 2):
print 'Usage: # python %s imagefilename' % argvs[0]
quit()
imagefilename = argvs[1]
try:
img=cv2.imread(imagefilename, 1)
except:
print 'faild to load %s' % imagefilename
quit()
#encode to jpeg format
#encode param image quality 0 to 100. default:95
#if you want to shrink data size, choose low image quality.
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),90]
result,encimg=cv2.imencode('.jpg',img,encode_param)
if False==result:
print 'could not encode image!'
quit()
#decode from jpeg format
decimg=cv2.imdecode(encimg,1)
cv2.imshow('Source Image',img)
cv2.imshow('Decoded image',decimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
I keep getting the following error:
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY), 90]
AttributeError: 'module' object has no attribute 'IMWRITE_JPEG_QUALITY'
I have tried a lot of things: reinstall opencv, convert cv2 to cv code and searched different forums but I keep getting this error. Am I missing something? Is there someone who can run this code without getting the error?
BTW: Other opencv code (taking pictures from webcam) runs without problems....
At the moment I save the image to a temp JPG file. Using the imencode function I want to create the jpg file in the memory.
Thanks in advance and with best regards.
The problem is not in your code, it should work, but it is with your OpenCV Python package. I can't tell you why is raising that error, but you can avoid it by changing the line of the encode_param declaration by this one:
encode_param=[1, 90]
OpenCV says something like
Corrupt JPEG data: premature end of data segment
or
Corrupt JPEG data: bad Huffman code
or
Corrupt JPEG data: 22 extraneous bytes before marker 0xd9
when loading a corrupt jpeg image with imread().
Can I somehow catch that? Why would I get this information otherwise?
Do I have to check the binary file on my own?
OpenCV (version 2.4) does not overwrite the basic error handling for libjpeg, making them 'uncatchable'. Add the following method to modules/highgui/src/grfmt_jpeg.cpp, right below the definition of error_exit():
METHODDEF(void)
output_message( j_common_ptr cinfo )
{
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
/* Default OpenCV error handling instead of print */
CV_Error(CV_StsError, buffer);
}
Now apply the method to the decoder error handler:
state->cinfo.err = jpeg_std_error(&state->jerr.pub);
state->jerr.pub.error_exit = error_exit;
state->jerr.pub.output_message = output_message; /* Add this line */
Apply the method to the encoder error handler as well:
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = error_exit;
jerr.pub.output_message = output_message; /* Add this line */
Recompile and install OpenCV as usual. From now on you should be able to catch libjpeg errors like any other OpenCV error. Example:
>>> cv2.imread("/var/opencv/bad_image.jpg")
OpenCV Error: Unspecified error (Corrupt JPEG data: 1137 extraneous bytes before marker 0xc4) in output_message, file /var/opencv/opencv-2.4.9/modules/highgui/src/grfmt_jpeg.cpp, line 180
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cv2.error: /var/opencv/opencv-2.4.9/modules/highgui/src/grfmt_jpeg.cpp:180: error: (-2) Corrupt JPEG data: 1137 extraneous bytes before marker 0xc4 in function output_message
(I've submitted a pull request for the above but it got rejected because it would cause issues with people reading images without exception catching.)
Hope this helps anyone still struggling with this issue. Good luck.
It could be easier to fix the error in the file instead of trying to repair the loading function of OpenCV. If you are using Linux you can use ImageMagick to make reparation to a set of images (is usual to have it installed by default):
$ mogrify -set comment 'Image rewritten with ImageMagick' *.jpg
This command changes a property of the file leaving the image data untouched. However, the image is loaded and resaved, eliminating the extra information that causes the corruption error.
If you need more information about ImageMagick you can visit their website: http://www.imagemagick.org/script/index.php
You cannot catch it if you use imread(). However there is imdecode() function that is called by imread(). Maybe it gives you more feedback. For this you would have to load the image into memory on your own and then call the decoder.
It boils down to: You have to dig through the OpenCV sources to solve your problem.
i had to deal with this recently and found a solution over here
http://artax.karlin.mff.cuni.cz/~isa_j1am/other/opencv/
i just need to make 2 edits # $cv\modules\highgui\src\grfmt_jpeg.cpp.
--- opencv-1.0.0.orig/otherlibs/highgui/grfmt_jpeg.cpp 2006-10-16 13:02:49.000000000 +0200
+++ opencv-1.0.0/otherlibs/highgui/grfmt_jpeg.cpp 2007-08-11 09:10:28.000000000 +0200
## -181,7 +181,7 ##
m_height = cinfo->image_height;
m_iscolor = cinfo->num_components > 1;
- result = true;
+ result = (cinfo->err->num_warnings == 0);
}
}
## -405,8 +405,9 ##
icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
}
}
- result = true;
+
jpeg_finish_decompress( cinfo );
+ result = (cinfo->err->num_warnings == 0);
}
}
I am using opencv python package to read some image and also met this error message. This error can not be catch by Python. But if you want to find which image is corrupted without recompiling opencv as #Robbert suggested, you can try the following method.
First, you can pinpoint the directory where the corrupt images reside, which is fairly easy. Then you go to the directory, and use mogrify command line tool provided by ImageMagick to change the image meta info, as suggest by #goe.
mogrify -set comment "errors fixed in meta info" -format png *.jpg
The above command will convert the original jpg image to png format and also clean the original image to remove errors in meta info. When you run mogrify command, it will also output some message about which image is corrupted in the directory so that you can accurately find the corrupted image.
After that, you can do whatever you want with the original corrupted jpg image.
Any one stumbles upon this post and reads this answer.
I had to get hold of a corrupted image file.
These websites can help you corrupt your file
Corrupt a file - The file corrupter you were looking for!
CORRUPT A FILE ONLINE
Corrupt my File
First and the third website was not that much useful.
Second website is interesting as I could set the amount of file that I need to corrupt.
OpenCV version I used here is 3.4.0
I used normal cv2.imread(fileLocation)
fileLocation Location of corrupted image file
OpenCV didn't show any error message for any of the corrupted files used here
First and Third website only gave one file and both had None stored in them, when I tried to print them
Second website did let me decide the amount of file that was needed to be corrupted
Corruption% Opencv message on printing the image
4% None
10% None
25% None
50% None Corrupt JPEG data: 3 extraneous bytes before marker 0x4f
75% None Corrupt JPEG data: 153 extraneous bytes before marker 0xb2
100% Corrupt JPEG data: 330 extraneous bytes before marker 0xc6 None
I guess the only check we have to make here would be
if image is not None:
Do your code or else pop an error
You can redirect stderr to a file, then after imread, search for the string "Huffman" inside that file. After searching the file, empty it. It works for me and now I am able to discard corrupted images and just process good ones.
If you load your image with imdecode, you can check errno :
std::vector<char> datas();
//Load yout image in datas here
errno = 0;
cv::Mat mat = cv::imdecode(datas, -1);
if (errno != 0)
{
//Error
}
(tested on OpenCV 3.4.1)
I found that the issue is in libjpeg. If OpenCV uses it, it gets error
Corrupt JPEG data: 22 extraneous bytes before marker 0xd9
You can try my solution to solve it. It disables JPEG during compilation. After that OpenCV cannot read/write, but it works.
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D WITH_JPEG=OFF -D WITH_IPP=OFF ..
I found an easy solution without the need to recompile openCV.
You can use imagemagick to detect the same errors, however it returns an error as expected. See the description here: https://stackoverflow.com/a/66283167/2887398