英文:
Why read the same picture with python and javascript with the help of opencv, the results are inconsistent?I think it should be same
问题
picture_4000*4000:
Python 代码是:
import cv2
pic_data = cv2.imread(path_to_picture)
pic_data 是:
pic_data
Out[21]:
array([[[125, 189, 204],
[125, 189, 204],
[125, 189, 204],
...,
[125, 189, 204],
[125, 189, 204],
[125, 189, 204]],
JavaScript 代码是:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<input type="file" id="js-input">
<img id="js-img" />
<script>
function onOpenCvReady() {
const input = document.getElementById('js-input');
const img = document.getElementById('js-img');
input.onchange = function () {
const file = event.target.files[0];
img.src = URL.createObjectURL(file);
console.log(file)
}
img.onload = function () {
const res = cv.imread(img);
console.log(res)
}
console.log('ready', cv)
}
</script>
<script src="https://docs.opencv.org/4.7.0/opencv.js" onload="onOpenCvReady()" type="text/javascript"></script>
</body>
</html>
可以使用 Chrome 打开 JavaScript 代码,并加载图片,读取的数据是:
问题
(忽略通道顺序的不一致性)
Python 代码读取的数据的第一个像素是 [125, 189, 204]
JavaScript 代码读取的数据的第一个像素是 [126, 190, 205]
我分别通过 Python 和 JavaScript 读取了同一张图片,但结果不同。我不知道为什么,我希望它们的结果相同。
更新
感谢关注这个问题的所有人。在阅读了rotem的答案和Christoph Rackwitz的评论后,我随机找到了其他几张图片并进行了相同的操作,发现Python和JavaScript的读取结果是一致的。这令人困惑,只有4000x4000的图片存在问题,在其他图片上没有复现这个问题。
例如,图片1.png:
Python 代码读取1.png的第一个像素是 [245, 213, 154]
JavaScript 代码读取1.png的第一个像素是 [245, 213, 154]
英文:
picture_4000*4000:
the python code is:
import cv2
pic_data = cv2.imread(path_to_picture)
the pic_data is:
pic_data
Out[21]:
array([[[125, 189, 204],
[125, 189, 204],
[125, 189, 204],
...,
[125, 189, 204],
[125, 189, 204],
[125, 189, 204]],
the javascript is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<input type="file" id="js-input">
<img id="js-img" />
<script>
function onOpenCvReady() {
const input = document.getElementById('js-input');
const img = document.getElementById('js-img');
input.onchange = function () {
const file = event.target.files[0];
img.src = URL.createObjectURL(file);
console.log(file)
}
img.onload = function () {
const res = cv.imread(img);
console.log(res)
}
console.log('ready', cv)
}
</script>
<script src="https://docs.opencv.org/4.7.0/opencv.js" onload="onOpenCvReady()" type="text/javascript"></script>
</body>
</html>
Can use Chrome to open javascript code. and load the image, the read data is:
Problem
(Ignore channel order inconsistencies)
The python code reads the first pixel of the data is [125, 189, 204]
The javascript code reads the first pixel of the data is [126, 190, 205]
I read the same picture separately through python and javascript, and get different results. I do not why, I want they hava the same results.
Update
Thanks to everyone who paid attention to this question. After reading rotem's answer and Christoph Rackwitz's comment. I randomly found several other pictures and did the same operation, and found that the reading results of python and javascript are consistent. This is very confusing, only picture_4000*4000 has the problem, did not reproduce the problem on other pictures.
Eg. the picture 1.png:
The python code reads the first pixel of 1.png is [245, 213, 154]
The javascript code reads the first pixel of 1.png is [245, 213, 154]
picture 1.png
picture 2.png
picture 3.jpg
答案1
得分: 3
It could be a bug in OpenCV.js, but it's more likely related to the exif metadata of the PNG image.
当然,它可能是OpenCV.js的一个错误,但更有可能与PNG图像的exif元数据相关。
When getting the exif information of the image using ExifTool:
在使用ExifTool获取图像的exif信息时:
exiftool Picture4000x4000.png
exiftool Picture4000x4000.png
There are all kinds of metadata that may affect the values of the pixels.
有各种各样的元数据可能会影响像素的值。
Example:
例如:
<!-- language: lang-none -->
<!-- language: lang-none -->
White Point X : 0.3127
White Point Y : 0.329
Red X : 0.64
Red Y : 0.33
Green X : 0.3
Green Y : 0.6
Blue X : 0.15
Blue Y : 0.06
白点X:0.3127
白点Y:0.329
红色X:0.64
红色Y:0.33
绿色X:0.3
绿色Y:0.6
蓝色X:0.15
蓝色Y:0.06
As far as I know, OpenCV in Python (and C++) ignores the metadata and keeps the "original" pixel values (without color conversion).
据我所知,Python(和C++)中的OpenCV忽略元数据,并保持“原始”像素值(没有颜色转换)。
I suppose OpenCV.js respects the metadata and applies some kind of color conversion process (OpenCV.js reads the metadata and adjusts the colors according to the metadata).
我猜想OpenCV.js尊重元数据,并应用某种颜色转换过程(OpenCV.js读取元数据并根据元数据调整颜色)。
We may use ImageMagick for stripping the exif data:
我们可以使用ImageMagick来剥离exif数据:
magick.exe Picture4000x4000.png -strip Picture4000x4000_copy.png
magick.exe Picture4000x4000.png -strip Picture4000x4000_copy.png
When loading the copy without the exif data, the value of the first pixel is [125, 204, 189]
- the same value as in Python.
在加载没有exif数据的副本时,第一个像素的值是[125, 204, 189]
- 与Python中相同的值。
The fact that OpenCV.js respects the metadata is undocumented, and I can't find a way to prevent it for getting the same values as in Python.
OpenCV.js尊重元数据的事实没有记录,我找不到一种方法来阻止它,以便获得与Python中相同的值。
Update:
更新:
As commented by Christoph Rackwitz, in Python OpenCV uses libpng for reading the PNG image, and in OpenCV.js, the Web browser reads the image to the canvas element and OpenCV reads the image from the canvas element.
The image reading process is different (the browser uses the exif data and may apply color conversion...).
正如Christoph Rackwitz所评论的,在Python中,OpenCV使用libpng来读取PNG图像,在OpenCV.js中,Web浏览器将图像读取到画布元素中,OpenCV从画布元素中读取图像。
图像读取过程不同(浏览器使用exif数据,可能应用颜色转换...)。
In the JavaScript code, we can see that OpenCV.js reads the image from the canvas element and not from the PNG file:
在JavaScript代码中,我们可以看到OpenCV.js从画布元素中读取图像,而不是从PNG文件中读取:
const img = document.getElementById('js-img');
const res = cv.imread(img);
const img = document.getElementById('js-img');
const res = cv.imread(img);
I can't find any attribute or CSS property for forcing the browser to ignore the exif data.
我找不到任何属性或CSS属性来强制浏览器忽略exif数据。
英文:
It could be a bug in OpenCV.js, but it's more likely related to the exif metadata of the PNG image.
When getting the exif information of the image using ExifTool:
exiftool Picture4000x4000.png
There are all kind of metadata that may affect the values of the pixels.
Example:
<!-- language: lang-none -->
White Point X : 0.3127
White Point Y : 0.329
Red X : 0.64
Red Y : 0.33
Green X : 0.3
Green Y : 0.6
Blue X : 0.15
Blue Y : 0.06
As far as I know, OpenCV in Python (and C++) ignores the metadata, and keep the "original" pixel values (without color conversion).
I suppose OpenCV.js respects the metadata, and applies some kind of color conversion process (OpenCV.js reads the metadata and adjust the colors according to the metadata).
We may use ImageMagick for striping the exif data:
magick.exe Picture4000x4000.png -strip Picture4000x4000_copy.png
When loading the copy without the exif data, the value of the first pixel is [125, 204, 189]
- same value as in Python.
The fact that OpenCV.js respects the metadata, is undocumented, and I can't find a way to prevent it, for getting same the values as in Python.
Update:
As commented by Christoph Rackwitz, in Python OpenCV uses libpng for reading the PNG image, and in OpenCV.js, the Web browser reads the image to canvas element and OpenCV reads the image from the canvas element.
The image reading process is different (the browser uses the exif data and may apply color conversion...).
In the JavaScript code, we can see that OpenCV.js reads the image from the canvas element and not from the PNG file:
const img = document.getElementById('js-img');
const res = cv.imread(img);
I can't find any attribute or CSS property for forcing the browser to ignore the exif data.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论