CentOS で yum update がエラーになる

CentOS 5.2 を入れて、

yum -y update

と入力すると・・・

[Errno -1] Metadata file does not match checksum
Trying other mirror.

というエラーが大量に出て、結局アップデート出来なかった。
 
原因不明で、ググッたけど良く分からず。
yum のオプションを見てみると、clear というオプションが使えるらしい。
そこで

yum clear all

とすると、あら不思議。
yum でアップデートが出来るようになった。

C# だけで画像のグレースケール化の処理

Bitmap クラスには、GetPixel 、SetPixel というメソッドがあるので、それを使って一ピクセルずつ処理してみた。
が!!!

これがまたクソ遅い。半端じゃない。

なので、バイト列を操作して画像を操作する方法を検索して、出来たのでメモ。
ちなみに、ピクセル操作と、バイト列操作では、100 倍くらい処理時間が違う。
SetPixel、GetPixel を使って処理すると、9000ms かかるが、
バイト列を取り出して操作すると、90ms で終わる、といった具合。

int 型とかビットシフトとかで演算してるけど、浮動小数点の演算が得意な CPU があるとか無いとかで、下手に int でやるより float でやったほうが早いとの話もあるが、試してないのでよく分からない。

using System;
using System.Drawing; // 参照設定に System.Drawing を追加する必要アリ
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
// 画面を用意
Bitmap bmp = Bitmap.FromFile("hoge.jpg");

// 画像データをメモリ上に固定?
BitmapData bmpdata = bmp.LockBits(
    new Rectangle(0, 0, bmp.Width, bmp.Height),
    ImageLockMode.ReadWrite,
    PixelFormat.Format32bppArgb
);

// グレイスケール用のアレ
int rp = (int)(0.298912 * 1024);
int gp = (int)(0.586611 * 1024);
int bp = (int)(0.114478 * 1024);

// バイト配列にコピー
byte[] ba = new byte[bmp.Width * bmp.Height * 4];
Marshal.Copy(bmpdata.Scan0, ba, 0, ba.Length);

// 処理
int pixsize = bmp.Width * bmp.Height * 4;
for (int i = 0; i < pixsize; i += 4)
{
    // 画像のバイト列って、ARGB じゃなくて、BGRAになってるっぽい??
    // リトルエンディアンか。
    byte g = (byte)((bp * ba[i + 0] + gp * ba[i + 1] + rp * ba[i + 2]) >> 10);
    ba[i + 0] = g;      // ブルー
    ba[i + 1] = g;      // グリーン
    ba[i + 2] = g;      // レッド
    ba[i + 3] = 0xFF;   // アルファ
}

// 元のところに書き込む。
Marshal.Copy(ba, 0, bmpdata.Scan0, ba.Length);

bmp.UnlockBits(bmpdata);

こうして出来た Bitmap を表示したり保存すると、グレイスケール化できている事を確認出来る。

もし、もっと複雑な画像処理や、画像認識を行いたいという場合は、OpenCV を使うと良さそう。

schima.hatenablog.com – OpenCvSharpをつかう

C# で画像の中に一致するパターンがあるか探す

C# で画像のりサイズを行う

正確には、Bitmap クラスで表される画像を、縦横比を維持したまま任意の矩形内に収まるようにリサイズして返すメソッド。
適当なコードなので、頭悪いかもしれない。

// 参照設定が無い場合は、そっちも必要。
using System.Drawing;
public static Bitmap ResizeImage(Bitmap image, double dw, double dh)
{
    double hi;
    double imagew = image.Width;
    double imageh = image.Height;

    if ((dh / dw) <= (imageh / imagew))
    {
        hi = dh / imageh;
    }
    else
    {
        hi = dw / imagew;
    }
    int w = (int)(imagew * hi);
    int h = (int)(imageh * hi);

    Bitmap result = new Bitmap(w, h);
    Graphics g = Graphics.FromImage(result);
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    g.DrawImage(image, 0, 0, result.Width, result.Height);

    return result;
}

C# で使える精度の高いタイマー

DateTime.Now とか、Environment.TickCount とか、これらの精度は、せいぜい15~16 ms 程度。
もっと精度が欲しい事もある。
そんなときは、Kernel32 の QueryPerformanceCounter と QueryPerformanceFrequency を使うとよろしい。詳しくは検索すると出てくる。
このクラスは、上記の API をラップしたもの。

using System;
using System.Runtime.InteropServices;
using System.Threading;

public class MyTimer
{
    [DllImport("Kernel32.DLL")]
    private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
    [DllImport("Kernel32.DLL")]
    private static extern bool QueryPerformanceFrequency(out long lpFrequency);

    private long startTime;
    private long stopTime;
    private long freq;

    public MyTimer()
    {
        startTime = 0;
        stopTime = 0;
        if (QueryPerformanceFrequency(out freq) == false)
        {
            throw new Exception();
        }
    }

    public void Start()
    {
        Thread.Sleep(0);
        QueryPerformanceCounter(out startTime);
    }

    public void Stop()
    {
        QueryPerformanceCounter(out stopTime);
    }

    public double Duration
    {
        get
        {
            return (stopTime - startTime) * 1000.0 / freq;
        }
    }
}

C# のネットワーク通信ソケットのタイムアウト設定

ソケットに対して、タイムアウト設定を行う。

// 接続待ち
Socket client = tcplistener.AcceptSocket();

// 2秒データを受信しなかったらタイムアウトになるように設定
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);

このコードでタイムアウトした場合

System.IO.IOException: 転送接続からデータを読み取れません。 ---> 
System.Net.Sockets.SocketException: 接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続できませんでした。
または接続済みのホストが応答しなかったため、確立された接続は失敗しました。

という内容の Exception が投げられる。

TcpClient でタイムアウト設定を行うなら

TcpClient client = new TcpClient("127.0.0.1", 12345);
client.ReceiveTimeout = 2000;
client.SendTimeout = 2000;

こんな感じで出来る。

送信タイムアウト(データを通信相手に一定時間送れなかった、受け取ってもらえなかった)
受信タイムアウト(通信相手から一定時間、データが届かなかった)
接続タイムアウト(通信相手に、ネットワーク的に接続できなかった、IPアドレス・ホスト名が間違っている、ポート番号が違う、相手のファイアウォールに阻まれた、など)

といった理由でタイムアウトが発生する事がある。

C# の TcpListener で接続してきたクライアントのIPアドレスを取得

// TcpListener で接続をうけ、Socket として取る。
Socket client = tcplistener.AcceptSocket();

// エンドポイントとかいうのをもらう
IPEndPoint endpoint = (IPEndPoint)client.RemoteEndPoint;

// そこから接続している相手の IPAddress が取れる。
IPAddress address = endpoint.Address;

// NetworkStream を作成。
NetworkStream stream = new NetworkStream(client);

C# の UDP通信をSocketで行う。TTL の指定 & ブロードキャスト

using System.Net;
using System.Net.Sockets;

TTL の指定

// 送信先
IPEndPoint remoteIP = new IPEndPoint(IPAddress.Parse("192.168.11.2"), 80);

// 送信データ
byte[] data = new byte[16];

// UDP ソケットの作成
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

// TTL を設定
// TTLとは…→ http://e-words.jp/w/TTL-1.html
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, 255);

// データを送信
s.SendTo(data, 0, data.Length, SocketFlags.None, remoteIP);

ブロードキャスト

IPEndPoint remoteIP = new IPEndPoint(IPAddress.Broadcast, 10002);

byte[] data = new byte[16];
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, 16);
// ブロードキャストはこれで許可を入れないといけないっぽい
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);

s.SendTo(data, data.Length, SocketFlags.None, remoteIP);

C# で マジックパケット(Wake On Lan、WOL)の送信

遠隔からコンピュータを起動する機能です。
起動されるコンピュータ側の設定も必要。

オーバーロードしてるから、長く見えるけど、要は一番下のメソッドが重要。

using System.Net;
using System.Net.Sockets;
using System.IO;
/// <summary>
/// マジックパケットを送信します。
/// </summary>
/// <param name="address">IPアドレス</param>
/// <param name="subnetmask">サブネットマスク</param>
/// <param name="physicalAddress">起動するマシンのMACアドレス</param>
private void SendMagicPacket(string address, string subnetmask, byte[] physicalAddress)
{
    SendMagicPacket(IPAddress.Parse(address), IPAddress.Parse(subnetmask), physicalAddress);
}

/// <summary>
/// マジックパケットを送信します。
/// </summary>
/// <param name="address">IPアドレス</param>
/// <param name="subnetmask">サブネットマスク</param>
/// <param name="physicalAddress">起動するマシンのMACアドレス</param>
private void SendMagicPacket(IPAddress address, IPAddress subnetmask, byte[] physicalAddress)
{
    uint uip = BitConverter.ToUInt32(address.GetAddressBytes(), 0);
    uint usub = BitConverter.ToUInt32(subnetmask.GetAddressBytes(), 0);

    uint result = uip | (usub ^ 0xFFFFFFFF);

    SendMagicPacket(new IPAddress(result), physicalAddress);
}

/// <summary>
/// ブロードキャストアドレス(255.255.255.255)に対してマジックパケットを送信します。
/// </summary>
/// <param name="physicalAddress">起動するマシンのMACアドレス</param>
private void SendMagicPacket(byte[] physicalAddress)
{
    SendMagicPacket(IPAddress.Broadcast, physicalAddress);
}

/// <summary>
/// 指定されたアドレスに対してマジックパケットを送信します。
/// 送信先のアドレスはブロードキャストアドレスである必要があります。
/// </summary>
/// <param name="broad">ブロードキャストアドレス</param>
/// <param name="physicalAddress">起動するマシンのMACアドレス</param>
private void SendMagicPacket(string broad, byte[] physicalAddress)
{
    SendMagicPacket(IPAddress.Parse(broad), physicalAddress);
}

/// <summary>
/// 指定されたアドレスに対してマジックパケットを送信します。
/// 送信先のアドレスはブロードキャストアドレスである必要があります。
/// </summary>
/// <param name="broad">ブロードキャストアドレス</param>
/// <param name="physicalAddress">起動するマシンのMACアドレス</param>
private void SendMagicPacket(IPAddress broad, byte[] physicalAddress)
{
    MemoryStream stream = new MemoryStream();
    BinaryWriter writer = new BinaryWriter(stream);
    for (int i = 0; i < 6; i++)
    {
        writer.Write((byte)0xff);
    }
    for (int i = 0; i < 16; i++)
    {
        writer.Write(physicalAddress);
    }

    UdpClient client = new UdpClient();
    client.EnableBroadcast = true;
    client.Send(stream.ToArray(), (int)stream.Position, new IPEndPoint(broad, 0));
}

C# でコンピュータのネットワークカードの名前の一覧を列挙

まぁ、2.0 ならこれで一覧がとれるかな?と。

using System.Net.NetworkInformation;
NetworkInterface[] nic = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface var in nic)
{
    Console.WriteLine(var.Description);
}

「MS TCP Loopback interface」 ってやつは、リストアップする際に除いたほうがイイ。
調べたら出てくると思うけど、localhost 接続用の仮想 NIC だったと思う。

WMI を使って、NIC一覧を取得するなら、こんな感じ。

using System.Management; //参照設定に System.Management を追加
ManagementClass mc = new ManagementClass("Win32_PerfRawData_Tcpip_NetworkInterface");
ManagementObjectCollection moc = mc.GetInstances();

foreach (ManagementObject mo in moc)
{
    // 情報を表示
    Console.WriteLine("名前     = {0}", mo["Name"]);
    Console.WriteLine("接続速度 = {0} Mbps", Convert.ToInt32(mo["CurrentBandwidth"]) / 1000 / 1000);

    Console.WriteLine("------");
}

無効になってる NIC は拾えないので(今は未検証だけど、たしかそうだった)、ご注意。