我有一个大的2400x1300 png文件,我想要切成10x10像素有序图像并将它们保存到一个单独的文件中。我找到了多种方法,但我不确定哪种方法对于这个大文件大小最有效。绩效是一个关键因素。
以下是对我来说最有希望的解决方案之一:
var deferred = _$q_.defer();
spyOn($q, 'all').and.returnValue(deferred.promise);
var results = "FAIL"
deferred.resolve(results);
$q.all().then(function(a){
expect(a).toBe("PASS") // -- this doesn't work
expect(a).toBe("FAIL") // -- this does work but is not what we want to test;
});
}
答案 0 :(得分:3)
由于您正在使用C ++,让我们切换到C ++ OpenCV API以简化操作(如果您真的需要,可以随意将其移植到旧的C API中。)
复制或不复制,这里的瓶颈将是编码并将图像写入磁盘。
最简单的方法是计算给定图块的边界矩形,然后使用cv::Mat::operator(...)
以O(1)成本获得子区域(ROI)(不复制)。然后使用适当的文件名调用cv::imwrite
进行保存(我将使用boost::format
生成文件名,但您也可以使用std::stringstream
。
示例代码:
#include <opencv2/opencv.hpp>
#include <boost/format.hpp>
#include <cstdint>
#include <chrono>
#include <iostream>
void process_tile(cv::Mat const& src
, cv::Size const& roi_size
, int32_t tile_col
, int32_t tile_row)
{
cv::Rect roi_bounds(tile_col * roi_size.width
, tile_row * roi_size.height
, roi_size.width
, roi_size.height);
cv::Mat roi(src(roi_bounds));
std::string file_name(str(boost::format("tiles/tile_%03d_%03d.png")
% tile_col % tile_row));
cv::imwrite(file_name, roi);
}
void save_tiles(cv::Mat const& src, cv::Size const& roi_size)
{
CV_Assert(src.cols % roi_size.width == 0);
CV_Assert(src.rows % roi_size.height == 0);
int32_t const TILE_COLS(src.cols / roi_size.width);
int32_t const TILE_ROWS(src.rows / roi_size.height);
for (int32_t r(0); r < TILE_ROWS; ++r) {
for (int32_t c(0); c < TILE_COLS; ++c) {
process_tile(src, roi_size, c, r);
}
}
}
int main()
{
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::microseconds;
// Generate some random test image...
cv::Mat src(1300, 2400, CV_8UC3);
cv::randu(src, 0, 256);
cv::Size const ROI_SIZE(10, 10); // width, height
high_resolution_clock::time_point t1 = high_resolution_clock::now();
save_tiles(src, ROI_SIZE);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(t2 - t1).count();
double t_ms(static_cast<double>(duration) / 1000.0);
std::cout << "Processed in " << t_ms << " ms\n";
return 0;
}
这里运行大约21.4秒,但是我发现它只使用了大约5%的可用CPU。看起来我们可以通过并行化来做得更好。
但首先,让我们考虑一下imwrite
。使用100像素图像,PNG使用的zlib压缩实际上没有太大区别,并且由于文件是几百字节(即比今天的文件系统块大小小得多),因此它对磁盘使用没有多大帮助。这意味着我们可以禁用不必要的压缩来加快速度。
std::vector<int32_t> compression_params{CV_IMWRITE_PNG_COMPRESSION , 0};
cv::imwrite(file_name, roi, compression_params);
这需要20.7秒 - 不是很大的收获,但仍然值得,因为我们没有失去任何东西。
让我们来看看并行化这个问题。 OpenCV为此提供了一个有用的工具 - cv::parallel_for_
,它为我们完成了大部分工作。
示例代码:
#include <opencv2/opencv.hpp>
#include <boost/format.hpp>
#include <cstdint>
#include <chrono>
#include <iostream>
#include <vector>
void process_tile(cv::Mat const& src
, cv::Size const& roi_size
, int32_t tile_col
, int32_t tile_row)
{
cv::Rect roi_bounds(tile_col * roi_size.width
, tile_row * roi_size.height
, roi_size.width
, roi_size.height);
cv::Mat roi(src(roi_bounds));
std::string file_name(str(boost::format("tiles/tile_%03d_%03d.png")
% tile_col % tile_row));
std::vector<int32_t> compression_params{ CV_IMWRITE_PNG_COMPRESSION , 0};
cv::imwrite(file_name, roi, compression_params);
}
class ParallelSaveTiles
: public cv::ParallelLoopBody
{
public:
ParallelSaveTiles(cv::Mat const& src, cv::Size const& roi_size)
: src(src)
, roi_size(roi_size)
{
}
virtual void operator()(cv::Range const& range) const
{
int32_t const TILE_COLS(src.cols / roi_size.width);
for (int32_t r(range.start); r < range.end; ++r) {
for (int32_t c(0); c < TILE_COLS; ++c) {
process_tile(src, roi_size, c, r);
}
}
}
private:
cv::Mat const& src;
cv::Size const& roi_size;
};
void save_tiles(cv::Mat const& src, cv::Size const& roi_size)
{
CV_Assert(src.cols % roi_size.width == 0);
CV_Assert(src.rows % roi_size.height == 0);
int32_t const TILE_ROWS(src.rows / roi_size.height);
ParallelSaveTiles parallel_impl(src, roi_size);
cv::parallel_for_(cv::Range(0, TILE_ROWS), parallel_impl);
}
int main()
{
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::microseconds;
cv::Mat src(1300, 2400, CV_8UC3);
cv::randu(src, 0, 256);
cv::Size const ROI_SIZE(10, 10); // width, height
high_resolution_clock::time_point t1 = high_resolution_clock::now();
save_tiles(src, ROI_SIZE);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(t2 - t1).count();
double t_ms(static_cast<double>(duration) / 1000.0);
std::cout << "Processed in " << t_ms << " ms\n";
return 0;
}
现在它运行大约5.3秒(在带有32 GB RAM的i7-4930K上,在Win10上写入SSD)。