master.dbo.fn_varbintohexsubstring が遅すぎるから、そこだけ c# で対応しました。
処理前
処理後(SSMS -> Excel)
use sample
go
------------------------------------
-- 入力画像データ格納テーブル
------------------------------------
/*
create table image_data(
id int not null identity(1,1) constraint PK_image_data primary key,
name varchar(100),
data varbinary(max)
)
go
*/
-- C:\Windows\Web\Wallpaper\Theme1\smile1.jpg -> D:\dev\data\smile1.bmp
------------------------------------
-- 画像登録
------------------------------------
/*
insert into image_data(name, data)
select
'smile1_24_192_120',
(select * from openrowset(bulk N'D:\dev\data\smile1.bmp', SINGLE_BLOB) as bin)
go
*/
------------------------------------
-- 出力画像データ格納テーブル
------------------------------------
/*
create table result_image(
pos int not null,
row_index int not null,
col_index int not null,
pix int not null,
constraint PK_result_image_rowcol primary key(row_index, col_index)
)
*/
------------------------------------
-- 前処理
------------------------------------
truncate table result_image
go
------------------------------------
-- ビットマップ情報取得
------------------------------------
with
------------------------------------
-- 固定パラメータ
------------------------------------
Param as (
select name, convert(varchar(max), data, 2) as data, data as rawdata from image_data where name = 'smile1_24_192_120'
),
------------------------------------
-- ビットマップファイルヘッダ
------------------------------------
BITMAPFILEHEADER as (
select
convert(char(2), dbo.Collection_Range(p.rawdata, 0, 2)) as bfType,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 2, 4))) as bfSize,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 6, 2))) as bfReserved1,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 8, 2))) as bfReserved2,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 10, 4))) as bfOffBits
from
Param as p
),
------------------------------------
-- ビットマップ情報ヘッダ
------------------------------------
BITMAPINFOHEADER as (
select
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 14, 4))) as biSize,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 18, 4))) as biWidth,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 22, 4))) as biHeight,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 26, 2))) as biPlanes,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 28, 2))) as biBitCount,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 30, 4))) as biCopmression,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 34, 4))) as biSizeImage,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 38, 4))) as biXPixPerMeter,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 42, 4))) as biYPixPerMeter,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 46, 4))) as biClrUsed,
convert(int, dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, 50, 4))) as biCirImportant
from
Param as p
),
------------------------------------
-- ビットマップ情報全体
------------------------------------
BitmapInfo as (
select
bf.*,
bi.*,
(bi.biBitCount/8 * bi.biWidth * bi.biHeight) as PixelCount
from
BITMAPFILEHEADER bf,
BITMAPINFOHEADER bi
),
------------------------------------
-- ピクセル数分のシーケンス生成
------------------------------------
Seq(rowIndex, maxRowCount) as (
select 0, (select PixelCount from BitmapInfo)
union all
select
rowIndex+1, maxRowCount
from
Seq
where
rowIndex < maxRowCount
),
------------------------------------
-- 各ピクセルのRGBを取得
------------------------------------
RawPixels as (
select
s.rowIndex as pos,
round(s.rowIndex / i.biWidth, 0) as row_index,
s.rowIndex % i.biWidth as col_index,
1 as alpha,
dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, i.bfOffBits + (s.rowIndex * 3) + 0, 1)) as red,
dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, i.bfOffBits + (s.rowIndex * 3) + 1, 1)) as green,
dbo.Collection_Reverse(dbo.Collection_Range(p.rawdata, i.bfOffBits + (s.rowIndex * 3) + 2, 1)) as blue,
i.*
from
Param as p,
Seq as s,
BitmapInfo i
where
s.rowIndex < s.maxRowCount / 3
),
------------------------------------
-- 固定パラメータ
------------------------------------
BinarizationParam as (
select 160 as threshold
),
------------------------------------
-- 2値化
------------------------------------
Binarization as (
select
p.pos,
p.row_index,
p.col_index,
(case
when p.red < BinarizationParam.threshold then 0
when p.green < BinarizationParam.threshold then 0
when p.blue < BinarizationParam.threshold then 0
else 1
end) as pix
from
RawPixels as p,
BinarizationParam
)
insert into
result_image
select
*
from
Binarization
option (maxrecursion 0)
------------------------------------
-- 列名一覧作成
------------------------------------
declare @col_list varchar(max) = ''
select
@col_list =
@col_list +
(case when len(@col_list) > 0 then ',' + char(13) else '' end) +
'(case ' +
'when max(case when col_index = ' + cast(col_index as varchar(max)) + ' then pix else 0 end) = 1 then ' +
''''' ' +
'else ' +
'''■'' ' +
'end) as c' + cast(col_index as varchar(max))
from
result_image
group by
col_index
order by
col_index
------------------------------------
-- 出力
------------------------------------
declare @sql varchar(max) =
'select ' + char(13) +
'row_index as r,' + char(13) +
@col_list + char(13) +
'from ' + char(13) +
'result_image ' + char(13) +
'group by row_index ' + char(13) +
'order by row_index desc'
--print @sql
execute sp_sqlexec @sql
go